Secret Santa Generator using Google Sheets - google-sheets

I'm in the process of using Google Sheets to make a Secret Santa Generator, but have come across a problem that I can't seem to get around. How do you ensure that people aren't given a giftee that is part of the same family group?
Currently I have a working system that looks at the first names of people and checks to see whether someone has been allocated themselves. But can this be done by taking into account first and last names to ensure that someone from the same family isn't given their partner?
Currently my formulas are as below;
A
B
C
D
E
F
1
Person
Rand No.
Rank
Giftee
Run Again?
2
1
Louise H.
=RAND()
=RANK(C2,C2:C5)
=VLOOKUP(D2,A2:B5,2,0)
=IF(B2=E2,"Error - Run Again","")
3
2
Matt H.
=RAND()
=RANK(C3,C3:C5)
=VLOOKUP(D3,A2:B5,2,0)
=IF(B3=E3,"Error - Run Again","")
4
3
Matt C.
=RAND()
=RANK(C4,C3:C5)
=VLOOKUP(D4,A2:B5,2,0)
=IF(B4=E4,"Error - Run Again","")
5
4
Liz C.
=RAND()
=RANK(C5,C3:C5)
=VLOOKUP(D5,A2:B5,2,0)
=IF(B5=E5,"Error - Run Again","")
6
5
Barbara D.
=RAND()
=RANK(C6,C3:C5)
=VLOOKUP(D6,A2:B5,2,0)
=IF(B6=E6,"Error - Run Again","")
7
6
Barbara D.
=RAND()
=RANK(C7,C3:C5)
=VLOOKUP(D7,A2:B5,2,0)
=IF(B7=E7,"Error - Run Again","")
And so on and so on for as many other people as required.
Anyone have some ideas to take the family situation into account?

use in row 2 and drag down:
=INDEX(LAMBDA(x, SINGLE(QUERY(SORT({x, REGEXEXTRACT(x, "\b\w+\b$")},
RANDARRAY(ROWS(x)), ), "select Col1 where not Col2 ends with '"&
REGEXEXTRACT(A2, "\b\w+\b$")&"'"&IF(ROW()=2,," and not Col1 matches '"&
TEXTJOIN("|", 1, C1:C$2)&"'"), )))(A$2:INDEX(A:A, MAX(ROW(A:A)*(A:A<>"")))))

Using your current setup try the following modification:
A
B
C
D
E
F
1
Person
Rand No.
Rank
Giftee
Run Again?
2
1
Louise H.
=RAND()
=RANK(C2,C$2:C$7)
=VLOOKUP(D2, $A$2:$B$7, 2, 0)
=IF(B2=E2,"Same Person- Run Again",IF(REGEXEXTRACT(B2," (.)")=REGEXEXTRACT(E2," (.)"),"Same Family - Run Again",""))
3
2
Matt H.
=RAND()
=RANK(C3,C$2:C$7)
=VLOOKUP(D3, $A$2:$B$7, 2, 0)
=IF(B3=E3,"Same Person- Run Again",IF(REGEXEXTRACT(B3," (.)")=REGEXEXTRACT(E3," (.)"),"Same Family - Run Again",""))
4
3
Matt C.
=RAND()
=RANK(C4,C$2:C$7)
=VLOOKUP(D4, $A$2:$B$7, 2, 0)
==IF(B4=E4,"Same Person- Run Again",IF(REGEXEXTRACT(B4," (.)")=REGEXEXTRACT(E4," (.)"),"Same Family - Run Again",""))
5
4
Liz C.
=RAND()
=RANK(C5,C$2:C$7)
=VLOOKUP(D5, $A$2:$B$7, 2, 0)
=IF(B5=E5,"Same Person- Run Again",IF(REGEXEXTRACT(B5," (.)")=REGEXEXTRACT(E5," (.)"),"Same Family - Run Again",""))
6
5
Barbara D.
=RAND()
=RANK(C6,C$2:C$7)
=VLOOKUP(D6, $A$2:$B$7, 2, 0)
=IF(B6=E6,"Same Person- Run Again",IF(REGEXEXTRACT(B6," (.)")=REGEXEXTRACT(E6," (.)"),"Same Family - Run Again",""))
7
6
Barbara D.
=RAND()
=RANK(C7,C$2:C$7)
=VLOOKUP(D7, $A$2:$B$7, 2, 0)
=IF(B7=E7,"Same Person- Run Again",IF(REGEXEXTRACT(B7," (.)")=REGEXEXTRACT(E7," (.)"),"Same Family - Run Again",""))
Result:
Explanation:
For the column F this compares the column B and E if they are the same person. This also extracts the last name (character after space) and compares them if they are from the same family.

If your list has always last name in the second name you could set this formula:
=byrow(B2:B,lambda(each,if(each="","",if(REGEXEXTRACT(each,"\s+[^\s]+")=REGEXEXTRACT(offset(each,0,3),"\s+[^\s]+"),"Same family - Run again",""))))
NOTE: the value 3 of offset determines the amount of columns that separates those two names. If it changes, change that number
One thing you could do in order not to get your giftee solutions re-arranged further than you'd like you could make a copy of B column and randomise:
This way you can randomise only when you want (and you could spare C and D columns)

Related

Formula to classify multiple, specific values in a range using Google Sheets

I could be doing this completely wrong, or I could be on the right path, I have no idea! I'm trying to grade a decision based on 3 criteria. The grades are AAA-A and BBB-B, etc. but for now I just need AAA-A and can figure out the rest.
Essentially, we want Col. J to populate based on what Col.'s G-I say. In my head it's super easy but I want to automate this step.
So I start with col.I and see the pairing.. AAA-A results are any of these "G/G" "LG/G" "G/LG" or "R/R". If it is one of those 4 pairings then we start at AA grade.
Then I check col.G (it doesnt matter now if I check H or G first), and if G>=.5 we grade it higher at AAA, if its less than .5 then do nothing and keep it at AA.
Then I look at col. H (or G if we started at H) and if it is a "Y" we grade down from AA to A. or AAA to AA. But it is "N" do nothing.
What I have so far is attached. It technically works for 3/4 of these cells but that could be a coincidence. The results column(J) should be row3 - AA, row4 - AA, row5 - AAA, row6 - AA.
And for one additional test, imagine: col.g = .64, col.h = Y, col.i = G/G -- then we want AA as the result.
Definitely the hardest test I've had in excel/sheets. I appreciate the help! Thanks in advance!
Formula I tried:
=Ifs((or(I3="G/G",I3="LG/G",I3="G/LG",I3="R/R"),"AA", and(or(I3="G/G",I3="LG/G",I3="G/LG",I3="R/R"),G3>0.5),"AAA",H3="Y","A")
Data Sample:
G
H
I
J
3
-0.07
N
R/R
AA
4
-0.46
N
R/R
AA
5
0.64
N
G/G
AA
6
0.76
Y
LG/G
AA
As presented, your formula simply returns an error, and seems like a misinterpretation of how Ifs works. However, it suggest you're trying to Nest If statements. And, from your description, I think that makes sense.
Assuming that's a valid interpretation, the following does what you want.
(At least as far as AAA-A is concerned).
=If(or(I3="G/G",I3="LG/G",I3="G/LG",I3="R/R"),if(G3<0.5,"AA","AAA"),if(H3="Y","A","Not an A"))
The BBB-B logic would be the same (just nested in where "Not an A" is).

Performing exact match when comparing variables in SPSS Statistics

I'm wondering if there's a way for me to perform an exact match compare in SPSS. Currently, using the following will return system missing (null) in cases where one variable is sysmis:
compute var1_comparison = * Some logic here.
compute var1_check = var1 = var1_comparison.
The results look like this (hypens representing null values):
ID var1 var1_comparison var1_check
1 3 3 1
2 4 3 0
3 - 2 -
4 1 1 1
5 - - -
What I want is this:
ID var1 var1_comparison var1_check
1 3 3 1
2 4 3 0
3 - 2 0
4 1 1 1
5 - - 1
Is this possible using just plain SPSS syntax? I'm also open to using the Python extension, though I'm not as familiar with it.
Here's a slightly different approach, using temporary scratch variables (prefixed by a hash (#)):
recode var1 var1_comparison (sysmis=-99) (else=copy) into #v1 #v2.
compute Check=(#v1 = #v2).
This is to recreate your example:
data list list/ID var1 var1_comparison.
begin data
1, 3, 3
2 , 4, 3
3, , 2
4, 1, 1
5, ,
end data.
Now you have to deal separately with the situation where both values are missing, and then complete the calculation in all other situations:
do if missing(var1) or missing(var1_comparison).
compute var1_check=(missing(var1) and missing(var1_comparison)).
else.
compute var1_check = (var1 = var1_comparison).
end if.

Fill missing data by interpolation in Google Spreadsheet

I have Google Spreadsheet with following data
A B D
1 Date Weight Computation
2 2015/12/09 =B2*2
3 2015/12/10 65 =B3*2
4 2015/12/11 =B4*2
5 2015/12/12 =B5*2
6 2015/12/14 62 =B6*2
7 2015/12/15 =B7*2
8 2015/12/16 61 =B8*2
9 2015/12/17 =B9*2
I want to graph the weight w.r.t. date, and/or use it with other columns that compute other quantities off the weight. However you will notice that there are some missing entries. What I want is another column which has data which is based on the Weight column with missing values interpolated and filled in. E.g.:
A B C D
1 Date Weight WeightI Computation
2 2015/12/09 65 =C2*2 # use first known value
3 2015/12/10 65 65 =C3*2
4 2015/12/11 64 =C4*2 # =(62-65)/3*(1)+65
5 2015/12/12 63 =C5*2 # =(62-65)/3*(2)+65
6 2015/12/14 62 62 =C6*2
7 2015/12/15 61.5 =C7*2 # =(61-62)/2*(1)+62
8 2015/12/16 61 61 =C8*2
9 2015/12/17 61 =C9*2 # use the last known value
In column C are values filled in using linear interpolation when I have to find missing data between two known points.
I believe this is a really simple and common use case, so I am sure its a trivial thing to do, but I am unable to find a solution using built in functions. I don't have much experience with spreadsheets either. I have spent hours experimenting with =INDEX, =MATCH, =VLOOKUP, =LINEST, =TREND etc., but I am not able to come up with something from the examples. The only solution that I could use was to create a custom function using Google Apps Script. Though my solution works, it seems to execute really very slowly. My spreadsheet is also huge.
Any pointers, solutions?
You might want to use forecast for which it may be more convenient first to separate out the dates you have readings from those you don't (and rearrange later). So with just three readings say:
A B
1 10/12/2015 65
2 14/12/2015 62
3 16/12/2015 61
and the dates for which values are required on the left below:
6 09/12/2015 65.6
7 11/12/2015 64.3
8 12/12/2015 63.6
9 15/12/2015 61.5
10 17/12/2015 60.2
The formula giving rise to 65.6 in B6 (and copied down from there to suit) is:
=forecast(A6,$B$1:$B$3,$A$1:$A$3)
This is not calculated in quite the way you show but may be considered slightly more accurate, in particular by extrapolating the missing end values, rather than just repeating their nearest available value.
Having calculated the values you would probably want to reassemble the data in date order. So I suggest copy B6:B10 and Edit, Paste special, Paste values only over the top and then sort to suit.
The chart below compares the results above (blue) with those in your OP (green) and marks the given data points:
Found an solution that satisfies most of my requirements using:
Used =FILTER() to first remove blank lines where data is not available (thanks for a tip from "pnuts").
And =MATCH() to lookup two consecutive rows from the filtered table. In my case I was able to use this function because column A is sorted and has no repetitions.
And then using line formula to interpolate values.
So the output becomes:
A B C D E
1 Date Weight FDdate FWeight IWeight
2 2015/05/09 2015/05/10 65.00 #N/A
3 2015/05/10 65.00 2015/05/13 62.00 65.00
4 2015/05/11 2015/05/15 61.00 64.00
5 2015/05/12 63.00
6 2015/05/13 62.00 62.00
7 2015/05/14 61.50
8 2015/05/15 61.00 61.00
9 2015/05/16 61.00
10 2015/05/17 61.00
Where cells C2 and D2 have the following range formula (minor note: the following formulas could of course be combined if columns A and B are adjacent):
C2 =FILTER($A$2:$A$10, NOT(ISBLANK($B$2:$B$10)))
D2 =FILTER($B$2:$B$10, NOT(ISBLANK($B$2:$B$10)))
Cells E2 through E10 contain the following line interpolation formula: [y = y1 + (y2 - y1) / (x2 - x1) * (x - x1)]:
E2 =(INDEX($D:$D, MATCH($A2, $C:$C, 1), 1))
+(INDEX($D:$D, MATCH($A2, $C:$C, 1) + 1, 1)
- INDEX($D:$D, MATCH($A2, $C:$C, 1), 1))
/(INDEX($C:$C, MATCH($A2, $C:$C, 1) + 1, 1)
- INDEX($C:$C, MATCH($A2, $C:$C, 1), 1))
*(INDEX($C:$C, MATCH($A2, $C:$C, 1), 1) - $A2) * -1
What this solution does not work for is when the first cell B2 does not have a value, where the formula result in #N/A. All this would have been much more efficient if we had something like =INTERPOLATE_LINE( A2, $A$2:$A$10, $B$2:$B$10 ) in google spreadsheet, but unfortunately this does not exist. Please correct me if I have missed it in my reading of the supported functions in google spreadsheet.
I found a solution which satisfies the requirements completely. I used a separate sheet so I could break up the calculation into pieces.
Create a new sheet. Enter the following formulas into Cells A2-F2, and then copy them down the page.
Cell A2: Copy your weight data into the first column. (In this example, the sheet name is Daily Record and the weights are recorded in column D.)
'Daily Record'!D2
Cell B2: Find the most recent recorded weight.
=INDEX(FILTER(A$2:A2,A$2:A2 <> ""),COUNT(FILTER(A$2:A2,A$2:A2 <> "")),1)
Cell C2: Count the number of days since the most recent weigh-in.
=IF(A2<>"",0,IF(ROW(C2)<3,0,C1+1))
Cell D2: Find the next recorded weight (from the current date or later.)
=IFERROR(INDEX(FILTER(A2:A,A2:A <> ""),1,1),"")
Cell E2: Count the number of days until the next weigh-in.
=IF(A2<>"",0,IF(E3="","",E3+1))
Cell F2: Calculate the interpolated weight.
=IF(A2 <> "", A2, IF(D2 = "", "", B2 + (D2-B2)*C2/(C2+E2)))

kdb simple table join unexpected result

I am trying out the example on how to join two tables found at http://code.kx.com/q/ref/lists/#join
The example shows:
t:([]a:1 2 3;b:`a`b`c)
r:([]c:10 20 30;d:1.2 3.4 5.6)
show t,`r
with this as the result:
a b c d
----------
1 a 10 1.2
2 b 20 3.4
3 c 30 5.6
However, when I try it in my q console, I am getting this result:
q)t,`r
`a`b!(1;`a)
`a`b!(2;`b)
`a`b!(3;`c)
`r
Can someone please explain what is happening, and what I am doing wrong?
It's a tick ('), not a backtick (`)
So it should be
t,'r
not
t,`r

minimal number of d flip-flops required for first seven Fibonacci numbers

I encountered a problem while preparing for a test.
What is the minimal number of d flip-flops required (along) with combinational logic to design a counter circuit that outputs the first seven Fibonacci numbers and then wraps around?
A) 3
B) 4
C) 5
D) 6
E) 7
My answer B
Seven Fibonacci numbers => 1 1 2 3 5 8 13.
To count to 13, we will need to 4 flip-flops hence 4 was my choice.
But the correct answer given is solutions was A.
Could someone please explain?

Resources