Related
Is there a more efficient way to return a list that contains a certain element from a list of lists?
For example:
lists = [['A', 'B', 'D', 'E', 'F', 'G', 'H'], ['C']]
If my input is C return the list ['C'] or if my input is D return the list = ['A', 'B', 'D', 'E', 'F', 'G', 'H']
What I've tried:
for lst in lists:
for n in range(len(lst)):
if element == lst[n]:
print(lst)
This is inefficient and I would like to know how to make it more efficient.
It might help you:
lists = [['A', 'B', 'D', 'E', 'F', 'G', 'H'], ['C']]
for lst in lists:
if element in lst:
print(lst)
You can try this:
for lst in lists:
if element in lst:
print(lst)
You can try this.
lists = [['A', 'B', 'D', 'E', 'F', 'G', 'H'], ['C']]
user_input = input("Please enter your input: ")
for item in lists:
if user_input in item:
print(item)
break
You should use the in operator:
def foo(lists, element):
for l in lists:
if element in l:
return l
print(foo([['A', 'B', 'D', 'E', 'F', 'G', 'H'], ['C']], 'C')) #prints ['C']
print(foo([['A', 'B', 'D', 'E', 'F', 'G', 'H'], ['C']], 'D')) #prints ['A', 'B', 'D', 'E', 'F', 'G', 'H']
Let me know if that helped!
Summary of answer: I used a function with parameters as the list, and the element. Basically I looped through each list in the list of lists, and checked if the element is in each list. If so, I return that list.
Your welcome:
lists = [['A', 'B', 'D', 'E', 'F', 'G', 'H'], ['C']]
element ='D'
lst = [lst for lst in lists if element in lst]
print(lst)
I have a list:
['A', 'B', 'C', ['D', ['E', 'F'], 'G'], 'H']
and I want to turn this into:
[['E', 'F'], ['D', 'G'], ['A', 'B', 'C', 'H']]
So basically I want the sublist on the deepest level of the list to come first in the new list and then counting down the level the remaining sublists.
This should work with any nested list.
If there are two sublists on the same level, then it doesn't really matter which one comes first.
['A', 'B', 'C', ['D', ['E', 'F'], 'G'], ['H', 'I', 'J']]
[['E', 'F'], ['D', 'G'], ['H', 'I', 'J'], ['A', 'B', 'C', 'H']] #this is fine
[['E', 'F'], ['H', 'I', 'J'], ['D', 'G'], ['A', 'B', 'C', 'H']] #this too
I thought of first using a function to determine on what level the deepest sublist is, but then again I don't know how to access items in a list based on their level or if that's even possible.
Been tinkering around this for far too long now and I think my head just gave up, hope someone can assist me with this problem!
You can use a recursive generator function:
def sort_depth(d, c = 0):
r = {0:[], 1:[]}
for i in d:
r[not isinstance(i, list)].append(i)
yield from [i for j in r[0] for i in sort_depth(j, c+1)]
yield (c, r[1])
def result(d):
return [b for _, b in sorted(sort_depth(d), key=lambda x:x[0], reverse=True) if b]
print(result(['A', 'B', 'C', ['D', ['E', 'F'], 'G'], 'H']))
print(result(['A', 'B', 'C', ['D', ['E', 'F'], 'G'], ['H', 'I', 'J']]))
print(result([[1, [2]], [3, [4]]]))
Output:
[['E', 'F'], ['D', 'G'], ['A', 'B', 'C', 'H']]
[['E', 'F'], ['D', 'G'], ['H', 'I', 'J'], ['A', 'B', 'C']]
[[2], [4], [1], [3]]
Here is a relatively straight-forward solution:
def sort_depth(d):
def dlists(obj, dep=0):
for x in filter(list.__instancecheck__, obj):
yield from dlists(x, dep-1)
yield [x for x in obj if not isinstance(x, list)], dep
return [x for x, y in sorted(dlists(d), key=lambda p: p[1])]
>>> [*sort_depth([[1, [2]], [3, [4]]])]
[[2], [4], [1], [3], []]
>>> [*sort_depth(['A', 'B', 'C', ['D', ['E', 'F'], 'G'], 'H'])]
[['E', 'F'], ['D', 'G'], ['A', 'B', 'C', 'H']]
The approach:
Collect all the sublists and annotate them with their (negative) nesting level, e.g. (['E', 'F'], -2)
Sort them by their nesting level
Extract the lists back from the sorted data
I have a nested list
x = [['a', 'b', 'c'], ['d'], ['e', 'f', ['g', ['h', 'i']]]]
I want to do all possible permutations of elements in sublists without going beyond corresponding sublist.
The expected output are variations of something like this:
[['c', 'b', 'a'], ['d'], ['f', 'e', ['g', ['i', 'h']]]]
[['d'], ['a', 'b', 'c'], ['f', 'e', [['h', 'i'], 'g']]]
Each element must be kept is kept in it's square bracket.
I Worte this generator:
def swap(x):
if isinstance(x, list):
res = np.random.choice(x, len(x), replace = False)
return [list(map(ff, res))]
else:
return x
It gives random variants of expected result, but i need to collect them all. How could I do it? Should I do:
my_list = []
for i in range(10000): # not necessary 10000, any huge number
my_list.append(ff(yy1))
And then apply unique function to my_list to select unique ones, or there is another option?
The isinstance()+itertools.permutations() is a good direction, just you need a product of them, and some tracking which permutation applies to what part of the tree(?) (I was thinking along generating all possible traversals of a tree):
import itertools
def plan(part,res):
if isinstance(part,list) and len(part)>1:
res.append(itertools.permutations(range(len(part))))
for elem in part:
plan(elem,res)
return res
def remix(part,p):
if isinstance(part,list) and len(part)>1:
coll=[0]*len(part)
for i in range(len(part)-1,-1,-1):
coll[i]=remix(part[i],p)
mix=p.pop()
return [coll[i] for i in mix]
else:
return part
def swap(t):
plans=itertools.product(*plan(t,[]))
for p in plans:
yield remix(t,list(p))
for r in swap([['a', 'b', 'c'], ['d'], ['e', 'f', ['g', ['h', 'i']]]]):
print(r)
plan() recursively finds all "real" lists (which have more than one element), and creates itertools.permutations() for them.
swap() calls plan(), and then combines the permutations into one single compound megapermutation using itertools.product()
remix() creates an actual object for a single megapermutation step. It is a bit complicated because I did not want to fight with tracking tree-position, instead remix() works backwards, going to the very last list, and swizzling it with the very last component of the current plan, removing it from the list.
It seems to work, though your example is a bit long, with simpler inputs it has manageable output:
for r in swap([['a', ['b', 'c']], ['d'], 'e']):
print(r)
[['a', ['b', 'c']], ['d'], 'e']
[['a', ['c', 'b']], ['d'], 'e']
[[['b', 'c'], 'a'], ['d'], 'e']
[[['c', 'b'], 'a'], ['d'], 'e']
[['a', ['b', 'c']], 'e', ['d']]
[['a', ['c', 'b']], 'e', ['d']]
[[['b', 'c'], 'a'], 'e', ['d']]
[[['c', 'b'], 'a'], 'e', ['d']]
[['d'], ['a', ['b', 'c']], 'e']
[['d'], ['a', ['c', 'b']], 'e']
[['d'], [['b', 'c'], 'a'], 'e']
[['d'], [['c', 'b'], 'a'], 'e']
[['d'], 'e', ['a', ['b', 'c']]]
[['d'], 'e', ['a', ['c', 'b']]]
[['d'], 'e', [['b', 'c'], 'a']]
[['d'], 'e', [['c', 'b'], 'a']]
['e', ['a', ['b', 'c']], ['d']]
['e', ['a', ['c', 'b']], ['d']]
['e', [['b', 'c'], 'a'], ['d']]
['e', [['c', 'b'], 'a'], ['d']]
['e', ['d'], ['a', ['b', 'c']]]
['e', ['d'], ['a', ['c', 'b']]]
['e', ['d'], [['b', 'c'], 'a']]
['e', ['d'], [['c', 'b'], 'a']]
24 permutations, as expected
Not particularly pythonic, but I would approach it by finding permutations of the indexes, as seen here:
from itertools import permutations
mylist= [[1], [1,2], [1,2,3]]
combinations = list(permutations([i for i in range(len(mylist))]))
print(combinations)
for item in combinations:
print([mylist[item[i]] for i in range(len(mylist))])
Output:
[(0, 1, 2), (0, 2, 1), (1, 0, 2), (1, 2, 0), (2, 0, 1), (2, 1, 0)]
[[1], [1, 2], [1, 2, 3]]
[[1], [1, 2, 3], [1, 2]]
[[1, 2], [1], [1, 2, 3]]
[[1, 2], [1, 2, 3], [1]]
[[1, 2, 3], [1], [1, 2]]
[[1, 2, 3], [1, 2], [1]]
Have you considered using itertools?
There are explicit combination and permutation tools available
From the docs:
itertools.permutations(iterable[, r])
Return successive r length
permutations of elements in the iterable.
If r is not specified or is None, then r defaults to the length of the
iterable and all possible full-length permutations are generated.
Permutations are emitted in lexicographic sort order. So, if the input
iterable is sorted, the permutation tuples will be produced in sorted
order.
Elements are treated as unique based on their position, not on their
value. So if the input elements are unique, there will be no repeat
values in each permutation.
itertools.combinations(iterable, r)
Return r length subsequences of elements from the input iterable.
Combinations are emitted in lexicographic sort order. So, if the input
iterable is sorted, the combination tuples will be produced in sorted
order.
Elements are treated as unique based on their position, not on their
value. So if the input elements are unique, there will be no repeat
values in each combination.
I have a dictionary that looks like this:
my_dict = {(1,0): ['A', 'B'],
(1,1): [[['E'], [['A', 'B'], ['C', 'D']]]],
(1,2): [],
(2,1): [[['E'], [['A', 'B'], ['C', 'F']]], [['S'], [[[['E'], [['A', 'B'], ['C', 'D']]]], [[['G'], [['H', 'J'], [[['E'], [['A', 'B'], ['C', 'F']]]]]]]]]]
}
How do I retrieve the first sublist I find that begins with ['S']? For the example above I would like to get:
answer = [['S'], [[[['E'], [['A', 'B'], ['C', 'D']]]], [[['G'], [['H', 'J'], [[['E'], [['A', 'B'], ['C', 'F']]]]]]]]]
I don't know how deep the 'S' is nested.
EDIT:
I attempted to do it recursively as follows:
def recursive_check(longlist):
for a_list in longlist:
if 'S' in a_lis:
return a_lis
else:
rec_check(a_list)
I received the following error:
RuntimeError: maximum recursion depth exceeded
EDIT: The list may look different and be nested differently every time.
def first_s(lst):
if not (isinstance(lst, list) and lst):
return None
if lst[0] == ['S']:
return lst
else:
for x in lst:
y = first_s(x)
if y:
return y
Using your my_dict:
>>> print first_s(my_dict.values())
[['S'], [[[['E'], [['A', 'B'], ['C', 'D']]]], [[['G'], [['H', 'J'], [[['E'], [['A', 'B'], ['C', 'F']]]]]]]]]
To get that list:
answer = my_dict[(2,1)][1]
It first gets the dictionary value with key of (2, 1), then takes that value (which is a list) and gets its item at index 1, which is the second item in the list (after 0).
>>> my_dict = {(1,0): ['A', 'B'],
... (1,1): [[['E'], [['A', 'B'], ['C', 'D']]]],
... (1,2): [],
... (2,1): [[['E'], [['A', 'B'], ['C', 'F']]], [['S'], [[[['E'], [['A', 'B'], ['C', 'D']]]], [[['G'], [['H', 'J'], [[['E'], [['A', 'B'], ['C', 'F']]]]]]]]]]
... }
>>> my_dict[(2,1)][1]
[['S'],
[[[['E'], [['A', 'B'], ['C', 'D']]]],
[[['G'], [['H', 'J'], [[['E'], [['A', 'B'], ['C', 'F']]]]]]]]]
(By the way, in your example, you are missing a comma after (1,2): []
...Update: which has now been fixed :) )
You can print element of s like my_dict[(2,1)][1][0] .
def nest(a,x):
m=False
for i in a:
if type(i)==list:
m=nest(i,x)
else:
if i==x:
return True
return m
def our_fun(my_dict):
for i in my_dict:
for j in my_dict[i]:
if nest(j,'S')==True:
return my_dict[i]
I checked for 'S' recursively.
I have the following code;
for d in range(0,len(newlist),4):
codewordgrid.append(list(codedmessage[d:d+6]))
This then prints something along the lines of this;
<<<CODEWORD GRID>>>
[['E', 'A'], ['E', 'A'], ['E', 'A'], ['F', 'C'], ['F', 'C'], ['F', 'C']]
[['F', 'C'], ['F', 'C'], ['F', 'A'], ['F', 'A'], ['F', 'A'], ['C', 'A']]
[['F', 'A'], ['C', 'A'], ['C', 'A'], ['C', 'A']]
[]
[]
[]
[]
[]
[]
Basically my aim is this - to print the list in an unlimited number of rows (so basically the message can be any length in rows), but to limit the number of columns to 4. So I would like the example to look more like this;
['E', 'A'], ['E', 'A'], ['E', 'A'], ['F', 'C']
['F', 'C'], ['F', 'C'], ['F', 'C'], ['F', 'C']
['F', 'A'], ['F', 'A'], ['F', 'A'], ['C', 'A']
['F', 'A'], ['C', 'A'], ['C', 'A'], ['C', 'A']
So just to reiterate, depending on how long the codedmessage is depends on the amount of rows, however I would like to limit the number of columns to 4 and I am unsure how to do this.
Many thanks.
It seems you have a copy-paste error here, as you just have to change the 6 to 4 when you do the slice. Also note that you use two different lists for the range and for the slice. I think you meant this:
for d in range(0,len(codedmessage),4):
codewordgrid.append(list(codedmessage[d:d+4]))
You can flatten the list with itertools:
chain = itertools.chain.from_iterable(your_nested_list):
for i in range(0, len(chain), 4):
print str(chain[i:i+4])[1:-1]
Or without itertools or other modules:
def eachToken(codewordgrid):
for element in codewordgrid:
for token in element:
yield token
for i, token in enumerate(eachToken(codewordgrid)):
print token, ("," if i % 4 else "\n"),
print
Numpy should be able to handle this pretty easily. If codedmessage is a list:
import numpy
codewordgrid = numpy.array(codedmessage).reshape(-1,4,2)
numpy.savetxt('codewordgrid.txt',codewordgrid,fmt='%s',delimiter=", ")
The only difference here is that there won't be a comma between codeword pairs.
e.g.
['E' 'A'], ['E' 'A'], ['E' 'A'], ['F' 'C']
['F' 'C'], ['F' 'C'], ['F' 'C'], ['F' 'C']
['F' 'A'], ['F' 'A'], ['F' 'A'], ['C' 'A']
['F' 'A'], ['C' 'A'], ['C' 'A'], ['C' 'A']