简体   繁体   中英

Excel Randbetween in excel puzzle

Here is my problem.

If cell A1 is not empty then I would like to choose a random name from a list (the names are Ben, Bill, Bob). The formula for this as follows: IF(A1<>"",INDEX(Q:Q,RANDBETWEEN(2,COUNTA(Q:Q))))

So far so good...

However, say A1 = Ben, Bill or Bob, then I would like my formula to exclude that name and pick another name from the list.

I can't figure out how to do this annoyingly. Any help is much appreciated, thanks.

Option for older versions:

=IF(A1<>"",INDEX(Q:Q,AGGREGATE(15,6,ROW(Q:Q)/((Q:Q<>A1)*(Q:Q<>"")),RANDBETWEEN(1,SUMPRODUCT((Q:Q<>"")*(Q:Q<>A1))))))

在此处输入图片说明

EDIT Pb in the comments notes that my filter can be reduced from

FILTER(FILTER(F:F,F:F<>""),FILTER(F:F,F:F<>"")<>A1) 

to

FILTER(F:F,(F:F<>"")*(F:F<>A1)) 

making the final function:

=INDEX(
  FILTER(F:F,(F:F<>"")*(F:F<>A1)),
  RANDBETWEEN(1, COUNTA(FILTER(F:F,(F:F<>"")*(F:F<>A1))))
)

If you are using a version of Excel that has FILTER, you can use it to filter the list of names, obtain the count, then pass that filtered list to INDEX along with a RANDBETWEEN using that count. Assuming your list of names is in Col F:

=INDEX(
  FILTER(FILTER(F:F, F:F<>""), FILTER(F:F, F:F<>"")<>A1),
  RANDBETWEEN(1, COUNTA(FILTER(FILTER(F:F, F:F<>""), FILTER(F:F, F:F<>"")<>A1)))
)

I am passing F to FILTER twice, once to remove empty rows and once to remove whatever name is in A1. This is the basic filtered list:

FILTER(FILTER(F:F,F:F<>""),FILTER(F:F,F:F<>"")<>A1)

As you can see, I pass that same filtered list to COUNTA and use that in RANDBETWEEN to get an INDEX from the list.

Here is a version using FILTERXML to filter the list. This should be supported in Windows versions back to 2012:

=INDEX(
  FILTERXML("<a><x>" & TEXTJOIN("</x><x>", TRUE, IF((F:F<>A1)*(F:F<>"")>0, F:F, "")) & "</x></a>", "//x"),
  RANDBETWEEN(1, SUM((F:F<>A1)*(F:F<>"")))
)

Here, we are going to use array products to generate a list of matching conditions. We can use the array product passed to sum to get the count for RANDBETWEEN, and also use it to filter the name list, then pass that list to TEXTJOIN to convert it into an xml string, then use FILTERXML to parse the node values back out into an array.

F:F=A1 will return a true/false array, and (F:F=A1)*(F:F<>"") will return a true/false array where F matches both conditions. And we can pass this to SUM to get a count:

=SUM((F:F<>A1)*(F:F<>""))

We can also pass this array to IF and get a list of matching names. We'll tell IF to return the values from F if TRUE or "" if FALSE.

IF((F:F<>A1)*(F:F<>"")>0, F:F, ""))

or to TEXTJOIN, telling it to ignore the empty values, using the separator to generate an xml string:

="<a><x>" & TEXTJOIN("</x><x>", TRUE, IF((F:F<>A1)*(F:F<>"")>0, F:F, "")) & "</x></a>"

And then use FILTERXML with //x to retrieve the values of the x nodes as an array. Then we pass that result to INDEX, along with RANDBETWEEN where we use the sum formula from before as the upper bound. A little hackier than the first one, but it should still work.

Using dynamic array functionality in ms 365, try:

在此处输入图片说明

Formula in B1 :

=@SORTBY(FILTER(D1:D3,D1:D3<>A1),RANDARRAY(2))

Note1: RANDARRAY() can be a bit more dynamic: RANDARRAY(COUNTA(D1:D3)-1) .

Note2: With LET() it can be written as =@LET(A,D1:D3,SORTBY(FILTER(A,A<>A1),RANDARRAY(COUNTA(A)-1)))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM