I have n lists each of length m. assume n*m is even. i want to get a randomly shuffled list with all elements, under the constraint that the elements in locations i,i+1 where i=0,2,...,n*m-2 never come from the same list. edit: other than this constraint i do not want to bias the distribution of random lists. that is, the solution should be equivalent to a complete random choice that is reshuffled until the constraint hold.
example:
list1: a1,a2
list2: b1,b2
list3: c1,c2
allowed: b1,c1,c2,a2,a1,b2
disallowed: b1,c1,c2,b2,a1,a2
A possible solution is to think of your number set as n chunks of item, each chunk having the length of m. If you randomly select for each chunk exactly one item from each lists, then you will never hit dead ends. Just make sure that the first item in each chunk (except the first chunk) will be of different list than the last element of the previous chunk.
You can also iteratively randomize numbers, always making sure you pick from a different list than the previous number, but then you can hit some dead ends.
Finally, another possible solution is to randomize a number on each position sequentially, but only from those which "can be put there", that is, if you put a number, none of the constraints will be violated, that is, you will have at least a possible solution.
A variation of b above that avoids dead ends: At each step you choose twice. First, randomly chose an item. Second, randomly choose where to place it. At the Kth step there are k optional places to put the item (the new item can be injected between two existing items). Naturally, you only choose from allowed places.
Money!
arrange your lists into a list of lists
save each item in the list as a tuple with the list index in the list of lists
loop n*m times
on even turns - flatten into one list and just rand pop - yield the item and the item group
on odd turns - temporarily remove the last item group and pop as before - in the end add the removed group back
important - how to avoid deadlocks?
a deadlock can occur if all the remaining items are from one group only.
to avoid that, check in each iteration the lengths of all the lists
and check if the longest list is longer than the sum of all the others.
if true - pull for that list
that way you are never left with only one list full
here's a gist with an attempt to solve this in python
https://gist.github.com/YontiLevin/bd32815a0ec62b920bed214921a96c9d
A very quick and simple method i am trying is:
random shuffle
loop over the pairs in the list:
if pair is bad:
loop over the pairs in the list:
if both elements of the new pair are different than the bad pair:
swap the second elements
break
will this always find a solution? will the solutions have the same distribution as naive shuffling until finding a legit solution?
Related
I have X lists of elements, each list containing a different number of elements (without repetitions inside a single list). I want to generate (if possible, 500) sequences of 3 elements, where each element belongs to a different list, and sequences do not repeat. So something like:
X (in this case 4) lists of elements: [A1,A2], [B1,B2,B3,B4], [C1], [D1,D2,D3,D4,D5]
possible results: [A1,B2,D2], [B3,C1,D2], [A1,B2,C1]... (here 500 sequences are impossible, so would be less)
I think I know how to do it with a nasty loop: join all the lists, random.sample(len(l),3) from the joint list, if 2 indices belong to the same list repeat, if not, check if the sequence was not found before. But that would be very slow. I am looking for a more pythonic or more mathematically clever way.
Perhaps a better way would be to use random.sample([A,B,C,D], 3, p=[len(A), len(B), len(C), len(D)]), then for each sequence from it randomly select an element from each group in the sequence, then check if a new sequence generated in this way hasn't been generated before. But again, a lot of looping.
Any better ideas?
Check itertools module (combination and permutation in particular).
You can get a random.choice() from the permutations of 3 elements from the X lists (thus selecting 3 lists), and for each of them get a random.choice() (random module).
I need some help to count the amount of combinations in a list array in python.
I need to count the amount of possible combinations between three letters in all of the elements and then find the most repeated one. eg, ABC, CDA, CCA, etc...
I have created a for loop to look in each element of the list, then I have another loop to check each combo of three letters and add it to a new list. I am not sure about how to count the amount of times a combination is repeated, and then to find the mode, I think I might use the max() function.
this is part of the code I have, but it does not work as I am expecting, because it is just adding each item of the list into an independent list.
lst = ["ABCDABCD", "ABDCABD", "ACCACABB", "BACDABC"]
for combo in lst:
for i in range (0,3):
combolst = []
combolst.append(lst[i].split())
print(combolst)
I am new to coding so that's why I'm here. Thanks!
(Assuming my math memory isn't garbage)
So okay, we are interested in combinations. Your code simply splits the list and creates a new one (as you said). Then we would use the combination formula : n!/(z!(n-z)!).
Where:
n is the number of elements, in this case the length of our string in question
z would be how many objects we wish to choose
Thus you would get:
for combo in lst:
n = math.factorial(len(combo))
r = math.factorial(3)
nMinR = math.factorial((len(combo) - 3))
result = n/(r*nMinR)
print(result)
This is for combination, if we want permutations (where order does matter)
for combo in lst:
n = math.factorial(len(combo))
nMinR = math.factorial((len(combo) - 3))
result = n/(nMinR)
print(result)
I hope I understood your question correctly. Here is some reading about combinations vs permutations (https://medium.com/i-math/combinations-permutations-fa7ac680f0ac). Keep in mind, the above code will only print out how many possible combinations or permutations are possible; it won't actually try to construct the possible values
Imagine we have a sorted list with size P. How can we choose N indices for which the values reflect the range of the list more smoothly. For example if our list is:
List=[0,0,0,0,0,0,0,0,0,0.1,0.1,0.9,0.91,0.91,0.92,0.99,0.99,0.99]
Then how we choose let's say 5 indices that somehow shows the full range of the list?
In this example it would be something like :
indices=[0,9,11,14,15]
The final indices list doesn't have to be exactly like the one I wrote here though
This will give you a starting point:
[List.index(x) for x in set(List)]
Now this may have too many elements but "somehow" is totally subjective and not a clear enough definition for what you need to do. As a default you can keep the first and last element, then randomly pick as many as you require from the "middle".
I am dealing with a problem where I need to keep track of the minimum number in a list. However, this list is constantly diminishing, say like from a million elements to a single element. I was looking for a way to avoid checking the minimum value everytime I got a one element smaller list. Like keeping track of the minimum element and if it is removed the next minimum becomes the minimum. I want to accomplish this in linear time.(It should be achievable given the mechanics of the problem)
What I thought of since I started that, I can use collections Counter to count elements in the list. Then I find the minimum(already O(2*n)), and everytime I remove an element, I subtract 1 from the value of the dictionary key. However when the minimum number's count is depleted, I would still require to find the second minimum element so it could replace it.
Please help me find a solution to this. I would say this is an interesting problem.
Let's say your program would take some time to sort that list
a = [10,9,10,8,7,6,5,4,3,2,1,1,1,0] # you're just removing
a = sorted(a) #sort ascending
# then you remove stuff from your list
# but always a[0] is minimum element
min = a[0] #you must be careful, there must be at least one item so check that before
#getting the min
So there is no need for searching it every time
This is homework but the lesson gives me the answer already. I'm having trouble putting the words from the answer to the line of code
#Calculate all the primes below 1000
result = [1]
candidates = range(3, 1000)
base = 2
product = base
while candidates:
while product < 1000:
if product in candidates:
candidates.remove(product)
product = product + base
result.append(base)
base = candidates[0]
product = base
del candidates[0]
result.append(base)
print result
This is a version of "The Sieve of Erastothenes."
This is the explanation that was given to me.
New things in this example…
The built-in function range actually returns a list that can be used like all other lists. (It includes the first index, but not the last.) A list can be used as a logic variable. If it is not empty, then it is true — if it is empty, then it is false. Thus, while candidates means “while the list named candidates is not empty” or simply “while there are still candidates”. You can write if someElement in someList to check if an element is in a list. You can write someList.remove(someElement) to remove someElement from someList. You can append an element to a list by using someList.append(something). Actually, you can use + too (as in someList = someList+[something]) but it is not as efficient. You can get at an element of a list by giving its position as a number (where the first element, strangely, is element 0) in brackets after the name of the list. Thus someList[3] is the fourth element of the list someList. (More on this below.) You can delete variables by using the keyword del. It can also be used (as here) to delete elements from a list. Thus del someList[0] deletes the first element of someList. If the list was [1,2,3] before the deletion, it would be [2,3] afterwards.
Before going on to explaining the mysteries of indexing list elements, I will give a brief explanation of the example.
This is a version of the ancient algorithm called “The Sieve of Erastothenes” (or something close to that). It considers a set (or in this case, a list) of candidate numbers, and then systematically removes the numbers known not to be primes. How do we know? Because they are products of two other numbers.
We start with a list of candidates containing numbers [2..999] — we know that 1 is a prime (actually, it may or may not be, depending on who you ask), and we wanted all primes below 1000. (Actually, our list of candidates is [3..999], but 2 is also a candidate, since it is our first base). We also have a list called result which at all times contains the updated results so far. To begin with, this list contains only the number 1. We also have a variable called base. For each iteration (“round”) of the algorithm, we remove all numbers that are some multible of this base number (which is always the smallest of the candidates). After each iteration, we know that the smallest number left is a prime (since all the numbers that were products of the smaller ones are removed — get it?). Therefore, we add it to the result, set the new base to this number, and remove it from the candidate list (so we won’t process it again.) When the candidate list is empty, the result list will contain all the primes. Clever, huh?
What I don't understand is where they say, 'we remove all numbers that are some multiple of this base number.' Where is that in the line of code? Can someone explain line by line what the program is doing? I am a newb at this trying to understand the mechanics on each line of code and why. Thanks for any assistance.
At the start of each of the while candidates: loops, product equals base. Then in that loop you have another loop, while products < 1000. At the end of this loop you increment product by base. So product goes through each multiple of base. You then remove all the values of product which is where you "remove multiples of the base number".
Basically what the program is doing is:
...
set product to base
for each candidate
for each multiple of base, referred to as 'product'
remove product from candidates
set base to new value
reset product to new base
...