Merging a list of lists - python

How do I merge a list of lists?
[['A', 'B', 'C'], ['D', 'E', 'F'], ['G', 'H', 'I']]
into
['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I']
Even better if I can add a value on the beginning and end of each item before merging the lists, like html tags.
i.e., the end result would be:
['<tr>A</tr>', '<tr>B</tr>', '<tr>C</tr>', '<tr>D</tr>', '<tr>E</tr>', '<tr>F</tr>', '<tr>G</tr>', '<tr>H</tr>', '<tr>I</tr>']

Don't use sum(), it is slow for joining lists.
Instead a nested list comprehension will work:
>>> x = [['A', 'B', 'C'], ['D', 'E', 'F'], ['G', 'H', 'I']]
>>> [elem for sublist in x for elem in sublist]
['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I']
>>> ['<tr>' + elem + '</tr>' for elem in _]
The advice to use itertools.chain was also good.

import itertools
print [('<tr>%s</tr>' % x) for x in itertools.chain.from_iterable(l)]
You can use sum, but I think that is kinda ugly because you have to pass the [] parameter. As Raymond points out, it will also be expensive. So don't use sum.

To concatenate the lists, you can use sum
values = sum([['A', 'B', 'C'], ['D', 'E', 'F'], ['G', 'H', 'I']], [])
To add the HTML tags, you can use a list comprehension.
html_values = ['<tr>' + i + '</tr>' for i in values]

Use itertools.chain:
>>> import itertools
>>> list(itertools.chain(*mylist))
['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I']
Wrapping the elements in HTML can be done afterwards.
>>> ['<tr>' + x + '</tr>' for x in itertools.chain(*mylist)]
['<tr>A</tr>', '<tr>B</tr>', '<tr>C</tr>', '<tr>D</tr>', '<tr>E</tr>', '<tr>F</tr>',
'<tr>G</tr>', '<tr>H</tr>', '<tr>I</tr>']
Note that if you are trying to generate valid HTML you may also need to HTML escape some of the content in your strings.

Related

How to return a list which contains certain element from lists of lists

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)

Combination of elements in a list with constraints

I am writing a python code and I need help with a task. I have a list of 8 elements
[A,B,C,D,E,F,G,H]
and I need to find all the combinations of shorter lists (4 elements) in lexicographic order such that two elements are taken from the subset A,C,E,G and the other two from B,D,F,H. I know that there is the library itertools, but I don't know how to combine its functions properly to perform this task
The wording of the question is unclear, but I think this is what you want:
array = ['f','g','d','e','c','b','h','a']
first = sorted(array[::2]) # ['c', 'd', 'f', 'h']
second = sorted(array[1::2]) # ['a', 'b', 'e', 'g']
I think this is what you want.
I need the set of all the new lists with length 4 such that the first two elements are taken from A,C,E,G and the other two are from B,D,F,H and I need them to be in lexicographic order.
We get the possible starting letters and ending letters then combine all possible pairs of each of them into all_lists:
from itertools import combinations
lst = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
starters = lst[::2] # ['A', 'C', 'E', 'G']
enders = lst[1::2] # ['B', 'D', 'F', 'H']
all_lists = []
for a in combinations(starters, 2):
for b in combinations(enders, 2):
all_lists.append(sorted(a + b))
print(all_lists) # Gives [['A', 'B', 'C', 'D'], ['A', 'B', 'C', 'F'], ['A', 'B', 'C', 'H'], ['A', 'C', 'D', 'F'], ['A', 'C', 'D', 'H'], ['A', 'C', 'F', 'H'], ...
print(all_lists == sorted(all_lists)) # False now
(Updated to sort each mini-list.)
Come to think of it you could maybe do the second part with itertools.product.

Combining lists of lists in python

I want to combine list of lists, here is the below sample
mylist = [[['a', 'b'], ['c', 'd']],
[['e', 'f'], ['g', 'h']]]
and the output should be:
output = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
I also tried using itertools, but here is what it returned
>>> combined = list(itertools.chain.from_iterable(mylist))
>>> combined
>>> [['a', 'b'], ['c', 'd'], ['e', 'f'], ['g', 'h']]
How I can achieve this ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
Can anyone highlight whats I'm missing?
The reason why the itertools method didn't work is because what you have isn't a list of lists, but a list of lists of lists. itertools is working properly, its just flattening the list once. Calling the exact same function again with the partially flattened list as an argument will work:
flat = list(itertools.chain.from_iterable(itertools.chain.from_iterable(mylist)))
Or, a simple list comprehension solution:
flat = [item for slist in mylist for sslist in slist for item in sslist]
This basically translates to:
for slist in mylist:
for sslist in slist:
for item in sslist:
flat.append(item)
Keep in mind, both these solutions are only good for dealing with double nesting. If there is a chance you will have to deal with even more nesting, I suggest you look up how to flatten arbitrarily nested lists.
As others have noted, you have two levels here so you need two calls to chain. But you don't actually need the from_iterable call; you can use the * syntax instead:
list(itertools.chain(*itertools.chain(*mylist)))
With numpy.ndarray.flatten():
import numpy as np
mylist = [ [['a', 'b'], ['c', 'd']], [['e', 'f'], ['g', 'h']] ]
a = np.array(mylist).flatten().tolist()
print(a)
The output:
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']

Python 3: return longest item in lists of lists

If i have this data:
a = [['a', 'b', 'b', 'v', 'd'],
['d', 'f', 'g'], ['q', 'w', 'e', 'r', 't', 'y'],
['x', '123', 'v', 'b'], ['g', 'h', 'i']]
I want to run a function (preferably single line) that will return 123 as is it has the longest string length in the list of lists. How can I do this?
The only thing I saw was finding the longest list in a list of lists, so this is a slightly different problem.
I think I would use itertools to flatten the nested lists and then use the built-in max:
from itertools import chain
data = [['a', 'b', 'b', 'v', 'd'],
['d', 'f', 'g'], ['q', 'w', 'e', 'r', 't', 'y'],
['x', '123', 'v', 'b'], ['g', 'h', 'i']]
print(max(chain.from_iterable(data), key=len))
# '123'
A more naive way would be to find the longest string in every list, then finding the longest string between these:
print(max((max(li, key=len) for li in data), key=len))
# '123'
Without any imports, and clean:
max((word for L in a for word in L), key=len)
There are a few approaches you could take (this first one is very similar to #DeepSpace's approach).
a = [['a', 'b', 'b', 'v', 'd'],
['d', 'f', 'g'], ['q', 'w', 'e', 'r', 't', 'y'],
['x', '123', 'v', 'b'], ['g', 'h', 'i']]
# flatten the list
flattened = [x for y in a for x in y]
longest_elem = max(flattened, key = lambda x: len(x))
You could also use numpy.argmax on the lengths of each string:
# find the longest element using numpy.argmax
import numpy as np
# store the lengths of each element in `flattened`
lengths = [len(x) for x in flattened]
# find the index of the largest element in `lengths`
longest_elem_index = np.argmax(lengths)
# index `flattened` with the longest element's index from `lengths`
longest_elem = flattened[longest_elem_index]

Merge lists in Python by placing every nth item from one list and others from another?

I have two lists, list1 and list2.
Here len(list2) << len(list1).
Now I want to merge both of the lists such that every nth element of final list is from list2 and the others from list1.
For example:
list1 = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
list2 = ['x', 'y']
n = 3
Now the final list should be:
['a', 'b', 'x', 'c', 'd', 'y', 'e', 'f', 'g', 'h']
What is the most Pythonic way to achieve this?
I want to add all elements of list2 to the final list, final list should include all elements from list1 and list2.
Making the larger list an iterator makes it easy to take multiple elements for each element of the smaller list:
list1 = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
list2 = ['x', 'y']
n = 3
iter1 = iter(list1)
res = []
for x in list2:
res.extend([next(iter1) for _ in range(n - 1)])
res.append(x)
res.extend(iter1)
>>> res
['a', 'b', 'x', 'c', 'd', 'y', 'e', 'f', 'g', 'h']
This avoids insert which can be expensive for large lists because each time the whole list needs to be re-created.
To preserve the original list, you could try the following:
result = copy.deepcopy(list1)
index = n - 1
for elem in list2:
result.insert(index, elem)
index += n
result
['a', 'b', 'x', 'c', 'd', 'y', 'e', 'f', 'g', 'h']
Using the itertools module and the supplementary more_itertools package, you can construct an iterable solution a couple different ways. First the imports:
import itertools as it, more_itertools as mt
This first one seems the cleanest, but it relies on more_itertools.chunked().
it.chain(*mt.roundrobin(mt.chunked(list1, n-1), list2))
This one uses only more_itertools.roundrobin(), whose implementation is taken from the itertools documentation, so if you don't have access to more_itertools you can just copy it yourself.
mt.roundrobin(*([iter(list1)]*(n-1) + [list2]))
Alternatively, this does nearly the same thing as the first sample without using any more_itertools-specific functions. Basically, grouper can replace chunked, but it will add Nones at the end in some cases, so I wrap it in it.takewhile to remove those. Naturally, if you are using this on lists which actually do contain None, it will stop once it reaches those elements, so be careful.
it.takewhile(lambda o: o is not None,
it.chain(*mt.roundrobin(mt.grouper(n-1, list1), list2))
)
I tested these on Python 3.4, but I believe these code samples should also work in Python 2.7.
What about the below solution? However I don't have a better one...
>>> list1 = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
>>> list2 = ['x', 'y']
>>> n = 2
>>> for i in range(len(list2)):
... list1.insert(n, list2[i])
... n += 3
...
...
>>> list1
['a', 'b', 'x', 'c', 'd', 'y', 'e', 'f', 'g', 'h']
n is 2 because the index of third element in a list is 2, since it starts at 0.
list(list1[i-1-min((i-1)//n, len(list2))] if i % n or (i-1)//n >= len(list2) else list2[(i-1)//n] for i in range(1, len(list1)+len(list2)+1))
Definitely not pythonic, but I thought it might be fun to do it in a one-liner. More readable (really?) version:
list(
list1[i-1-min((i-1)//n, len(list2))]
if i % n or (i-1)//n >= len(list2)
else
list2[(i-1)//n]
for i in range(1, len(list1)+len(list2)+1)
)
Basically, some tinkering around with indexes and determining which list and which index to take next element from.
Yet another way, calculating the slice steps:
list1 = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
list2 = ['x', 'y']
n = 3
res = []
m = n - 1
start, end = 0, m
for x in list2:
res.extend(list1[start:end])
res.append(x)
start, end = end, end + m
res.extend(list1[start:])
>>> res
['a', 'b', 'x', 'c', 'd', 'y', 'e', 'f', 'g', 'h']
list1 = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
list2 = ['x', 'y']
n = 3
new = list1[:]
for index, item in enumerate(list2):
new[n * (index + 1) - 1: n * (index + 1) - 1] = item
print(new)
I admire #David Z's use of more_itertools. Updates to the tools can simplify the solution:
import more_itertools as mit
n = 3
groups = mit.windowed(list1, n-1, step=n-1)
list(mit.flatten(mit.interleave_longest(groups, list2)))
# ['a', 'b', 'x', 'c', 'd', 'y', 'e', 'f', 'g', 'h']
Summary: list2 is being interleaved into groups from list1 and finally flattened into one list.
Notes
groups: n-1 size sliding windows, e.g. [('a', 'b'), ('c', 'd'), ('e', 'f'), ('g', 'h')]
interleave_longest is presently equivalent to roundrobin
None is the default fillvalue. Optionally remove with filter(None, ...)
Maybe here is another solution, slice the list1 the correct index then add the element of list2 into list1.
>>> list1 = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
>>> list2 = ['x', 'y']
>>> n = 3
>>> for i in range(len(list2)):
... list1 = list1[:n*(i+1) - 1] + list(list2[i]) + list1[n*(i+1)-1:]
...
>>> list1
['a', 'b', 'x', 'c', 'd', 'y', 'e', 'f', 'g', 'h']

Categories