manipulate list of list using random and restrictions - python

I have two lists a and b.
a=[[3, 1], [3, 2, 3], [5, 1, 4, 8], [3, 5], [10, 1, 3, 6, 7],[2,1,2]]
b=[[4], [3], [9], [5], [21],[5]]
List of list a is interpreted as follows.
a[0]=[3,1]. This means I want 3 items, where item 1 must be included.
a[-1]=[2,1,2] I want 2 items, where item 1 and item 2 must
be included.
a[2] = [5,1,4,8] I want 5 items, where item 1, item 4 and item 8 must be included.
List of list b is the available list of item from which list a can take from.
b[0]=[4] this means item 1, item 2, item 3 and item 4 is available. This is linked
to a[0]
b[-1]=[5] item 1, item 2, item 3, item 4 and item 5 is available. This is linked to a[-1]
b[2]=[9] this means i have 9 items is available. This is linked to a[2]
I'm trying to create a new list of list c such that it produces the following result.
For a[0]=[3,1] and b[0]=[4] it should produce the following result [1,2,4]
For a[-1]=[2,1,2] and b[-1]=[5] it should produce [1,2]
For a[2] = [5,1,4,8] and b[2]=[9] should produce [1,4,8,3,9]
What I have tried so far:
import random
a=[[3, 1], [3, 2, 3], [5, 1, 4, 8], [3, 5], [10, 1, 3, 6, 7],[2,1,2]]
b=[[4], [3], [9], [5], [21],[5]]
c=[sorted(random.sample(range(1, j[0]+1), int(i[0]))) for i,j in zip(a,b)]
print(c) # produces [[1, 3, 4], [1, 2, 3], [1, 3, 4, 6, 9], [1, 4, 5], [2, 5, 6, 7, 13, 15, 16, 19, 20, 21], [3, 4]]
As you can see, list c does not take into account those restrictions that I need.
Desired output will look something like this.
c= [[1,2,4],[2,3,1],[1,4,8,3,9],[5,1,3],[1,3,6,7,2,5,9,10,20,21],[1,2]]

You can run a loop over the two lists and construct a remaining_items list to randomly sample from -
c = []
for constraints, items in zip(a, b):
num_items, *required_items = constraints
pick_list = list(_ for _ in range(1, items[0] + 1) if _ not in required_items)
num_items_to_pick = num_items - len(required_items)
remaining_items = random.sample(pick_list, num_items_to_pick)
print(required_items + remaining_items)
c.append(required_items + remaining_items)
Output
[[1, 2, 3],
[2, 3, 1],
[1, 4, 8, 3, 6],
[5, 3, 1],
[1, 3, 6, 7, 18, 2, 14, 21, 19, 15],
[1, 2]]

Related

From a list of lists, how do I find lists with n elements in common

I have a list of lists
foo = [[1, 2, 4, 17], [1, 2, 4, 12], [1, 2, 5, 17]]
I am interested in finding all possible groups of lists which share n elements.
Expected results:
Lists sharing 3 elements
group containing [1,2,4]: [[1, 2, 4, 17], [1, 2, 4, 12]]
group containing [1,2,17]: [[1, 2, 4, 17], [1, 2, 5, 17]]
Lists sharing 2 elements
group containing [1,2]: [[1, 2, 4, 17], [1, 2, 4, 12], [1, 2, 5, 17]]
group containing [1,4]: [[1, 2, 4, 17], [1, 2, 4, 12]]
group containing [2,4]: [[1, 2, 4, 17], [1, 2, 4, 12]]
group containing [1,17]: [[1, 2, 4, 17], [1, 2, 5, 17]]
group containing [2,17]: [[1, 2, 4, 17], [1, 2, 5, 17]]
What I tried so far
Intersection of list: it does not answer my problem as i have no control over the number of elements I'll like my lists to share.
What I want to try but seems really complicated and they must be a more convenient way
For each list, define all combinations of the list minus one element (i.e. subset).
Loop over the remaining lists and store the ones containing the subset in a dictionary
I posted a minimal example here, but in reality I have a list of hundred of list, each containing 6 elements, so I am afraid of combinatorial explosion as well.
If anyone could offers some guidance or tricks, that will be great.
Many thanks,
Best
I don't think there is an easy way around generating all combinations with n elements for each inner list. But every combination needs to be checked only once:
from itertools import combinations
import random
n = 3
foo = [[random.randint(0,100) for _ in range(6)] for _ in range(500)]
#foo = [[1, 2, 4, 17], [1, 2, 4, 12], [1, 2, 5, 17]]
checked = set() # already checked combinations
result = []
for lst in foo:
cbs = combinations(lst, n)
for comb in cbs:
if not comb in checked:
groups = [l for l in foo if all(i in l for i in comb)]
if len(groups) > 1:
result.append((comb, groups))
checked.add(comb)
print(result)
Output:
[((1, 2, 4), [[1, 2, 4, 17], [1, 2, 4, 12]]),
((1, 2, 17), [[1, 2, 4, 17], [1, 2, 5, 17]])]
Performance:
For the randomly generated list with 500 sublists, values from 0-100 or 0-1000 inside the sublists and n=2 or n=3, the code took a few seconds to complete.
This should help you:
from itertools import combinations
def isSubset(comb,lst):
it = iter(lst)
return all(c in it for c in comb)
foo = [[1, 2, 4, 17], [1, 2, 4, 12], [1, 2, 5, 17]]
n = 3
print('-'*100)
print(f"n = {n}")
existing = []
for index in range(len(foo)):
combs = combinations(foo[index],n)
for comb in combs:
occurrences = 0
curr_lst = []
for lst in foo:
if isSubset(comb,lst):
if comb not in existing:
occurrences += 1
curr_lst.append(lst)
if occurrences >= 2:
if occurrences == 2:
print('-' * 100)
print(f"Groups containing {comb}")
[print(elem) for elem in curr_lst]
else:
print(lst)
existing.append(comb)
Output:
----------------------------------------------------------------------------------------------------
n = 3
----------------------------------------------------------------------------------------------------
Groups containing (1, 2, 4)
[1, 2, 4, 17]
[1, 2, 4, 12]
----------------------------------------------------------------------------------------------------
Groups containing (1, 2, 17)
[1, 2, 4, 17]
[1, 2, 5, 17]
Output for n=2:
----------------------------------------------------------------------------------------------------
n = 2
----------------------------------------------------------------------------------------------------
Groups containing (1, 2)
[1, 2, 4, 17]
[1, 2, 4, 12]
[1, 2, 5, 17]
----------------------------------------------------------------------------------------------------
Groups containing (1, 4)
[1, 2, 4, 17]
[1, 2, 4, 12]
----------------------------------------------------------------------------------------------------
Groups containing (1, 17)
[1, 2, 4, 17]
[1, 2, 5, 17]
----------------------------------------------------------------------------------------------------
Groups containing (2, 4)
[1, 2, 4, 17]
[1, 2, 4, 12]
----------------------------------------------------------------------------------------------------
Groups containing (2, 17)
[1, 2, 4, 17]
[1, 2, 5, 17]

Is there anyway to get random indexes of a list in a new list in python

I am trying to get indexes of a list store into a new list.
for example,
A = ['A', 'B', 'C',....,'Z']
and B list will select random no of indexes of A list like.
B = [[2,None,None], [1,None,None], [3,None,None],.....,[0, None,None]]
where list limit is, suppose, 10 and None will be replaced with the random no between 0 to 20 and finally the list of resultant look like,
result = [[2, 2, 3], [0, 4, 5], [8, 2, 4], [3, 8, 9]]
the first element in a sublist refers to the list A and the 2nd and third elements refer to the random selection of numbers between 0 to 10
Using random.sample.
import random
result = [random.sample(range(len(A)), 1) + random.sample(range(10), 2) for _ in range(10) ]
If you don't mind possible replication of values in the elements you can use a list comprehension, using random.randrange to generate the numbers:
result = [[random.randrange(26), random.randrange(10), random.randrange(10)] for _ in range(10)]
print(result)
Sample output:
[[18, 8, 1], [24, 1, 4], [24, 6, 5], [1, 4, 4], [7, 0, 9], [10, 7, 7], [0, 6, 9], [0, 9, 4], [6, 4, 4], [4, 2, 7]]
If you want to ensure no replication in each of elements of the list, you can use zip and random.sample to put together 3 lists of unique values and select values from those:
result = [[a, b, c] for a, b, c in zip(random.sample(range(26), 10), random.sample(range(10), 10), random.sample(range(10), 10))]
print(result)
Sample output:
[[2, 0, 1], [21, 4, 0], [11, 1, 4], [10, 7, 5], [15, 3, 3], [23, 6, 8], [25, 5, 2], [1, 9, 7], [24, 8, 9], [6, 2, 6]]
Think this basis for you
A = ['A', 'B', 'C','Z']
B = [[2,None,None], [1,None,None], [3,None,None],[0, None,None]]
for newb in B:
if newb[1] is None:
newb[1] = random.randrange(0,10)
if newb[2] is None:
newb[2] = random.randrange(0,10)
print(B)
it do like
[[2, 2, 2], [1, 6, 9], [3, 5, 7], [0, 6, 2]]

loop through a list and create arrays showing all sequences of n in a row, followed by the next iteration in the list

If I have a list, I'm attempting to create a function that will go through the list and create arrays of size n.
For example:
list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] with n = 3
Running the function would generate [0, 1, 2], [1, 2, 3], [2, 3, 4] etc.
If you want to write it as a function, you have two inputs:
input_list and n
Then you should iterate over the list, and make sub-lists with length n, i've done this using list slices.
def print_list(input_list,n):
for i in range(len(input_list)):
if len(input_list[i:i+n])==n:
print(input_list[i:i+n])
Here you can find the output of this program with an example :
>>> print_list([1,2,3,4,5,6],3)
[1, 2, 3]
[2, 3, 4]
[3, 4, 5]
[4, 5, 6]
You can use zip with lists with incremented offsets:
lst = list(range(11))
n = 3
out = []
for sub in zip(*[lst[i:] for i in range(n)]):
out.append(list(sub))
Since zip stops at the end of the final list, you won’t have any empty values at the end. And in a function:
def func(list, n):
return [[*x] for x in zip(*[list[i:] for i in range(n)])]
See if this works for you:
x=[0,1,2,3,4,5,6,7,8,9,10,11]
def lst(lst, n):
for x in range(len(lst)-(n-1)):
print(lst[x:x+n])
lst(x,3)
Output:
[0, 1, 2]
[1, 2, 3]
[2, 3, 4]
[3, 4, 5]
[4, 5, 6]
[5, 6, 7]
[6, 7, 8]
[7, 8, 9]
[8, 9, 10]
[9, 10, 11]

How for loop works in python?

I have a lists of lists in variable lists something like this:
[7, 6, 1, 8, 3]
[1, 7, 2, 4, 2]
[5, 6, 4, 2, 3]
[0, 3, 3, 1, 6]
[3, 5, 2, 14, 3]
[3, 11, 9, 1, 1]
[1, 10, 2, 3, 1]
When I write lists[1] I get vertically:
6
7
6
3
5
11
10
but when I loop it:
for i in list:
print(i)
I get this horizontally.
7
6
1
8
3
etc...
So, how it works? How can I modify loop to go and give me all vertically?
Short answer:
for l in lists:
print l[1]
Lists of lists
list_of_lists = [ [1, 2, 3], [4, 5, 6], [7, 8, 9]]
for list in list_of_lists:
for x in list:
print x
Here is how you would print out the list of lists columns.
lists = [[7, 6, 1, 8, 3],
[1, 7, 2, 4, 2],
[5, 6, 4, 2, 3],
[0, 3, 3, 1, 6],
[3, 5, 2, 14, 3],
[3, 11, 9, 1, 1],
[1, 10, 2, 3, 1]]
for i in range(0, len(lists[1])):
for j in range(0, len(lists)):
print lists[j][i],
print "\n"

substracting elements of a dictionary

I have a dictionary made up of lists:
>>> triplets.get(k)
[[1, 3, 15], [1, 3, 13], [1, 3, 11], [1, 3, 9], [1, 3, 8], [1, 3, 5], [1, 4, 15]
and also dictionaries:
>>> cset1.get(k)
[set([5])]
>>> cset2.get(k)
[[1, 8], [1, 9], [1, 11]]
I want to delete elements of triplets which contain the element of cset1 or both elements of cset2, i.e. I want to delete [1,3,5] which contains [5] and also [1, 3, 8], [1, 3, 9], [1, 3, 11] which contain both elements of cset2.
I have the following piece of code (which doesn't do anything at all):
CDln = len(triplets.get(k))
for ii in range(CDln):
if cset1.get(k) in triplets.get(k)[ii] or cset2.get(k) in triplets.get(k)[ii]:
print "delete element of triplets in location:", ii
I cannot figure out how to delete those elements from dictionary triplets (I use the print statement as a dummy of what I want).
I am not quite sure if I got you right, but take a look and comment please:
k = 42 #whatever
triplets = {k: [[1, 3, 15], [1, 3, 13], [1, 3, 11], [1, 3, 9], [1, 3, 8], [1, 3, 5], [1, 4, 15]]}
cset1 = {k: [set([5])]}
cset2 = {k: [{1, 8}, {1, 9}, {1, 11}]} #changed this to sets
triplets[k] = [x for x in triplets[k] if
all (y - set(x) for y in cset1[k]) and
all (y - set(x) for y in cset2[k])
]
print(triplets[k])
I'm not sure what ii is, but I think this is what you want.
b = cset1[k]
c = cset2[k]
triplets[k] = filter(
lambda lst:
any(lambda x: x in b, lst) or
any(lambda c1: all(lambda x: x in c1), c),
triplets[k]
]
But:
I wonder why you have a cset1 and cset2. It seems as though, you should just have cset2, whose value is
[[5], [1, 8], [1, 9], [1, 11]]

Categories

Resources