Generating a list of random lists - python

I'm new to Python, so I might be doing basic errors, so apologies first.
Here is the kind of result I'm trying to obtain :
foo = [
["B","C","E","A","D"],
["E","B","A","C","D"],
["D","B","A","E","C"],
["C","D","E","B","A"]
]
So basically, a list of lists of randomly permutated letters without repeat.
Here is the look of what I can get so far :
foo = ['BDCEA', 'BDCEA', 'BDCEA', 'BDCEA']
The main problem being that everytime is the same permutation. This is my code so far :
import random
import numpy as np
letters = ["A", "B", "C", "D", "E"]
nblines = 4
foo = np.repeat(''.join(random.sample(letters, len(letters))), nblines)
Help appreciated. Thanks

The problem with your code is that the line
foo = np.repeat(''.join(random.sample(letters, len(letters))), nblines)
will first create a random permutation, and then repeat that same permutation nblines times. Numpy.repeat does not repeatedly invoke a function, it repeats elements of an already existing array, which you created with random.sample.
Another thing is that numpy is designed to work with numbers, not strings. Here is a short code snippet (without using numpy) to obtain your desired result:
[random.sample(letters,len(letters)) for i in range(nblines)]
Result: similar to this:
foo = [
["B","C","E","A","D"],
["E","B","A","C","D"],
["D","B","A","E","C"],
["C","D","E","B","A"]
]
I hope this helped ;)
PS: I see that others gave similar answers to this while I was writing it.

np.repeat repeats the same array. Your approach would work if you changed it to:
[''.join(random.sample(letters, len(letters))) for _ in range(nblines)]
Out: ['EBCAD', 'BCEAD', 'EBDCA', 'DBACE']
This is a short way of writing this:
foo = []
for _ in range(nblines):
foo.append(''.join(random.sample(letters, len(letters))))
foo
Out: ['DBACE', 'CBAED', 'ACDEB', 'ADBCE']

Here's a plain Python solution using a "traditional" style for loop.
from random import shuffle
nblines = 4
letters = list("ABCDE")
foo = []
for _ in range(nblines):
shuffle(letters)
foo.append(letters[:])
print(foo)
typical output
[['E', 'C', 'D', 'A', 'B'], ['A', 'B', 'D', 'C', 'E'], ['A', 'C', 'B', 'E', 'D'], ['C', 'A', 'E', 'B', 'D']]
The random.shuffle function shuffles the list in-place. We append a copy of the list to foo using letters[:], otherwise foo would just end up containing 4 references to the one list object.
Here's a slightly more advanced version, using a generator function to handle the shuffling. Each time we call next(sh) it shuffles the lst list stored in the generator and returns a copy of it. So we can call next(sh) in a list comprehension to build the list, which is a little neater than using a traditional for loop. Also, list comprehesions can be slightly faster than using .append in a traditional for loop.
from random import shuffle
def shuffler(seq):
lst = list(seq)
while True:
shuffle(lst)
yield lst[:]
sh = shuffler('ABCDE')
foo = [next(sh) for _ in range(10)]
for row in foo:
print(row)
typical output
['C', 'B', 'A', 'E', 'D']
['C', 'A', 'E', 'B', 'D']
['D', 'B', 'C', 'A', 'E']
['E', 'D', 'A', 'B', 'C']
['B', 'A', 'E', 'C', 'D']
['B', 'D', 'C', 'E', 'A']
['A', 'B', 'C', 'E', 'D']
['D', 'C', 'A', 'B', 'E']
['D', 'C', 'B', 'E', 'A']
['E', 'D', 'A', 'C', 'B']

Related

Separate a List in 2 or more lists

If I have the following list of lists for example:
[['A', 'B', 'C'], ['A', 'D', 'E', 'B', 'C']]
How could I get a List with lists of only 3 elems each (in case they are greater than 3 elems), if they have not more than 3 elems we don't need to do nothing, we just need to separate the elems with more than 3 like the following:
[['A', 'B', 'C'], ['A', 'D', 'E'], ['D', 'E', 'B'], ['E', 'B', 'C']]
Could you help me with this ? I've been trying for a long time without success, kinda new to Python.
Edit:
Well, I resolved this in this way:
def separate_in_three(lista):
paths = []
for path in lista:
if len(path) <= 3:
paths.append(path)
else:
for node in range(len(path)-1):
paths.append(path[:3])
path.pop(0);
if(len(path) == 3):
paths.append(path)
break
return paths
Seems to resolve my problem, I could use the list in comprehension, were it would be much more efficient than the way I did ?
Thanks for the help btw !
you can use list comprehension like below.
l = [['A', 'B', 'C'], ['A', 'D', 'E', 'B', 'C','Z']]
[l[0]] + [l[1][i: i+len(l[0])] for i in range(1 + len(l[1]) - len(l[0]))]

Python: How to generate list with items repeating in two lists

I have two lists of items:
list_1 = ['A', 'B', 'C', 'C', 'D']
list_2 = ['C', 'C', 'F', 'A', 'G', 'D', 'C']
I want to create a new list with the elements that are in the two lists. Like this:
['A', 'C', 'C', 'D']
Notice that it should take in mind that any item can repeat in list several times and should be in the new list as many times as it is repeated in both lists. For instance, 'C' is repeated 2 times in list_1 and 3 times in list_2 so it appears 2 times in the result.
The classic method to do it will be:
import copy
result = []
list_2 = fruit_list_2.copy()
for fruit in fruit_list_1:
if fruit in list_2:
result.append(fruit)
list_2.remove(fruit)
but I am interested to do it by generation lists: [number for number in numbers if number > 0]. Is it possible?
If you aren't terribly concerned about the ordering of the new list, you can use collections.Counter.
>>> list((Counter(list_1) & Counter(list_2)).elements())
['A', 'C', 'C', 'D']
& takes the intersection of the two as multi-sets, with the minimum count used for common elements. The elements method returns the items in the result as an iterator, hence the list wrapper`.
read about collections.Counter
from collections import Counter
list_3 = list((Counter(list_1) & Counter(list_2)).elements())
I think it's as simple as:
list_1 = ['A', 'B', 'C', 'C', 'D']
list_2 = ['C', 'C', 'F', 'A', 'G', 'D', 'C']
list_3 = [x for x in list_1 if x in list_2]
print(list_3)
# returns ['A', 'C', 'C', 'D']
Try this:
[common for common in list_1 if common in list_2]
Happy learning...:)

My Python module returns wrong list

I done the following Python script which should return a list of sublists.
def checklisting(inputlist, repts):
result = []
temprs = []
ic = 1;
for x in inputlist
temprs.append(x)
ic += 1
if ic == repts:
ic = 1
result.append(temprs)
return result
Example: If I called the function with the following arguments:
checklisting(['a', 'b', 'c', 'd'], 2)
it would return
[['a', 'b'], ['c', 'd']]
or if I called it like:
checklisting(['a', 'b', 'c', 'd'], 4)
it would return
[['a', 'b', 'c', 'd']]
However what it returns is a weird huge list:
>>> l.checklisting(['a','b','c','d'], 2)
[['a', 'b', 'c', 'd'], ['a', 'b', 'c', 'd'], ['a', 'b', 'c', 'd'], ['a', 'b', 'c', 'd']]
Someone please help! I need that script to compile a list with the data:
['water tax', 20, 'per month', 'electric tax', 1, 'per day']
The logic behind it is that it would separe sequences in the list the size of repts into sublists so it can be better and easier organized. I don't want arbitrary chunks of sublists as these in the other question don't specify the size of the sequence correctly.
Your logic is flawed.
Here are the bugs: You keep appending to temprs. Once repts is reached, you need to remove elements from temprs. Also, list indexes start at 0 so ic should be 0 instead of 1
Replace your def with:
def checklisting(inputlist, repts):
result = []
temprs = []
ic = 0;
for x in inputlist:
temprs.append(x)
ic += 1
if ic == repts:
ic = 0
result.append(temprs)
temprs = []
return result
Here is link to working demo of code above
def split_into_sublists(list_, size):
return list(map(list,zip(*[iter(list_)]*size)))
#[iter(list_)]*size this creates size time lists, if
#size is 3 three lists will be created.
#zip will zip the lists into tuples
#map will covert tuples to lists.
#list will convert map object to list.
print(split_into_sublists(['a', 'b', 'c', 'd'], 2))
[['a', 'b'], ['c', 'd']]
print(split_into_sublists(['a', 'b', 'c', 'd'], 4))
[['a', 'b', 'c', 'd']]
I got lost in your code. I think the more Pythonic approach is to slice the list. And I can never resist list comprehensions.
def checklisting(inputlist, repts):
return [ input_list[i:i+repts] for i in range(int(len(input_list)/repts)) ]

Start loop after certain element in list is reached

How do I start executing code in a for loop after a certain element in the list has been reached. I've got something that works, but is there a more pythonic or faster way of doing this?
list = ['a', 'b', 'c', 'd', 'e', 'f']
condition = 0
for i in list:
if i == 'c' or condition == 1:
condition = 1
print i
One way would to be to iterate over a generator combining dropwhile and islice:
from itertools import dropwhile, islice
data = ['a', 'b', 'c', 'd', 'e', 'f']
for after in islice(dropwhile(lambda L: L != 'c', data), 1, None):
print after
If you want including then drop the islice.
A little simplified code:
lst = ['a', 'b', 'c', 'd', 'e', 'f']
start_index = lst.index('c')
for i in lst[start_index:]:
print i

How to maintain consistency in list?

I have a list like
lst = ['a', 'b', 'c', 'd', 'e', 'f']
I have a pop position list
p_list = [0,3]
[lst.pop(i) for i in p_list] changed the list to ['b', 'c', 'd', 'f'], here after 1st iteration list get modified. Next pop worked on the new modified list.
But I want to pop the element from original list at index [0,3] so, my new list should be
['b', 'c', 'e', 'f']
Lots of reasonable answers, here's another perfectly terrible one:
[item for index, item in enumerate(lst) if index not in plist]
You could pop the elements in order from largest index to smallest, like so:
lst = ['a', 'b', 'c', 'd', 'e', 'f']
p_list = [0,3]
p_list.sort()
p_list.reverse()
[lst.pop(i) for i in p_list]
lst
#output: ['b', 'c', 'e', 'f']
Do the pops in reversed order:
>>> lst = ['a', 'b', 'c', 'd', 'e', 'f']
>>> p_list = [0, 3]
>>> [lst.pop(i) for i in reversed(p_list)][::-1]
['a', 'd']
>>> lst
['b', 'c', 'e', 'f']
The important part here is that inside of the list comprehension you should always call lst.pop() on later indices first, so this will only work if p_list is guaranteed to be in ascending order. If that is not the case, use the following instead:
[lst.pop(i) for i in sorted(p_list, reverse=True)]
Note that this method makes it more complicated to get the popped items in the correct order from p_list, if that is important.
Your method of modifying the list may be error prone, why not use numpy to only access the index elements that you want? That way everything stays in place (in case you need it later) and it's a snap to make a new pop list. Starting from your def. of lst and p_list:
from numpy import *
lst = array(lst)
idx = ones(lst.shape,dtype=bool)
idx[p_list] = False
print lst[idx]
Gives ['b' 'c' 'e' 'f'] as expected.

Categories

Resources