Python combining items in a list of lists python - python

I have three items in a list of lists:
test = [[a,b,c],[d,e,f],[g,h,i]]
I want it to look like this:
test = [[a,b,c,d,e,f],[g,h,i]]
what is the best way to do this in python?
Thanks for the help

>>> test = [[1,2,3], [4,5,6], [7,8,9]]
>>> test[0].extend(test.pop(1)) # OR test[0] += test.pop(1)
>>> test
[[1, 2, 3, 4, 5, 6], [7, 8, 9]]

test = [test[0] + test[1], test[2]]

If you want to flatten of an arbitrary slice, use a slice assignment and a list comprehension on the part you want to flatten.
This flatten from position n to end of the list:
>>> test = [[1,2,3],[4,5,6],[7,8,9],[10,11,12],[13,14,15]]
>>> n=2
>>> test[n:]=[[i for s in test[n:] for i in s]]
>>> test
[[1, 2, 3], [4, 5, 6], [7, 8, 9, 10, 11, 12, 13, 14, 15]]
This flattens up to n (but including n):
>>> test = [[1,2,3],[4,5,6],[7,8,9],[10,11,12],[13,14,15]]
>>> test[0:n]=[[i for s in test[0:n] for i in s]]
>>> test
[[1, 2, 3, 4, 5, 6], [7, 8, 9], [10, 11, 12], [13, 14, 15]]
This flattens in the middle (from and including n to include the additional groups specified):
>>> test = [[1,2,3],[4,5,6],[7,8,9],[10,11,12],[13,14,15]]
>>> test[n:n+2]=[[i for s in test[n:n+2] for i in s]]
>>> test
[[1, 2, 3], [4, 5, 6], [7, 8, 9, 10, 11, 12], [13, 14, 15]]
Flatten all the sublists:
>>> test = [[1,2,3],[4,5,6],[7,8,9],[10,11,12],[13,14,15]]
>>> n=len(test)
>>> test[0:n]=[[i for s in test[0:n] for i in s]]
>>> test
[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]]
Note that in each case the slice on the assignment side is the same as the slice on the list comprehension side. This allows the use of the same slice object for each.
For the last case of flattening the whole list, obviously, you can just do test=[[i for s in test for i in s]] but the fact the logic is consistent allows you to wrap this in a function use a slice object.

You could combine the first two items in the list of list with the + operator and you should use '' for your strings
test = [['a','b','c'],['e','f','g'],['h','i','j']]
result = [test[0] + test[1], test[2]]
print result
output:
[['a', 'b', 'c', 'e', 'f', 'g'], ['h', 'i', 'j']]

Using the more_itertools package:
import more_itertools as mit
list(mit.chunked(mit.flatten(test), 6))
# [[1, 2, 3, 4, 5, 6], [7, 8, 9]]

Related

Fastest way to split a list into a list of lists based on another list of lists

Say I have a list that contains 5 unique integers in the range of 0 to 9.
import random
lst = random.sample(range(10), 5)
I also have a list of lists, which is obtained by splitting integers from 0 to 19 into 6 groups:
partitions = [[8, 12], [2, 4, 16, 19], [1, 6, 7, 13, 14, 17], [3, 15, 18], [5, 9, 10, 11], [0]]
Now I want to split lst based on the reference partitions.
For example, if I have
lst = [0, 1, 6, 8, 9]
I expect the output to be a list of lists like this:
res = [[0], [1, 6], [8], [9]]
I want the algorithm to be as fast as possible. Any suggestions?
res=[]
for sublist in partitions: # go through all sublists in partitions
match = [i for i in lst if i in sublist] # find matching numbers in sublist and lst
if match: # if it is empty don't append it to res
res.append(match)
# at this point res is [[8], [1, 6], [9], [0]]
print(sorted(res)) # use sorted to get desired output
I don't know if this is the fastest algorithm but it works
import random
lst = random.sample(range(10), 5)
partitions = [[8, 12], [2, 4, 16, 19], [1, 6, 7, 13, 14, 17], [3, 15, 18], [5, 9, 10, 11], [0]]
sequence = []
result = []
for i in range(5):
for j in range(len(partitions)):
if lst[i] in partitions[j]:
if j in sequence:
where = sequence.index(j)
result[where] += [lst[i]]
else:
result += [[lst[i]]]
sequence += [j]
break
print(result)

How to merge two lists into a new list sequantially? [duplicate]

This question already has answers here:
Interleave multiple lists of the same length in Python [duplicate]
(11 answers)
Closed 3 years ago.
I'm working with lists in Python 3.x.
I want to merge two lists:
list1 = [1, 2, 3, 4]
list2 = [7, 8, 9, 19]
Expected output like this:
list3 = [1, 7, 2, 8, 3, 9, 4, 19]
I am not allowed to use any advanced data structures and need to write in a pythonic way.
Simply we can use list comprehension like this:
list1 = [1, 2, 3, 4]
list2 = [7, 8, 9, 19]
list3 = [v for v1_v2 in zip(list1, list2) for v in v1_v2]
assert list3 == [1, 7, 2, 8, 3, 9, 4, 19]
For example:
from itertools import chain
list(chain(*zip(v1, v2)))
zip() the two lists together then flatten with itertools.chain.from_iterable():
>>> from itertools import chain
>>> list1 = [1,2,3,4]
>>> list2 = [7,8,9,19]
>>> list(chain.from_iterable(zip(list1, list2)))
[1, 7, 2, 8, 3, 9, 4, 19]
You can simply use reduce from functools over a sum of the two lists using zip
from functools import reduce
from operator import add
list1 = [1,2,3,4]
list2 = [7,8,9,19]
x = list(reduce(add, zip(list1, list2)))
x
[1, 7, 2, 8, 3, 9, 4, 19]
Try the below code:
list1 = [1, 2, 3, 4]
list2 = [7, 8, 9, 19]
new_list = []
for i in range(len(list1)):
new_list.extend([list1[i], list2[i]])
print(new_list)
Output:
[1, 7, 2, 8, 3, 9, 4, 19]

Python array segmented in ranges

I have the following array [1, 4, 7, 9, 2, 10, 5, 8] and I need to separate the array in 3 different arrays: one for values between 0 and 3, anther for 3 to 6 and anther for 6 and 25.The result must be something like that:
array1 = [1, 2]
array2 = [4, 5]
array3 = [7, 9, 10, 8]
Any idea about how to do it simple?
First, define your "pole" numbers
Second, generate your intervals from those "pole" numbers
Third, define as many lists as there are intervals.
Then for each interval, scan the list and appends items in the relevant list if they belong to the interval
code:
source = [1, 4, 7, 9, 2, 10, 5, 8]
poles = (0,3,6,25)
intervals = [(poles[i],poles[i+1]) for i in range(len(poles)-1)]
# will generate: intervals = [(0,3),(3,6),(6,25)]
output = [list() for _ in range(len(intervals))]
for out,(start,stop) in zip(output,intervals):
for s in source:
if start <= s <stop:
out.append(s)
print(output)
result:
[[1, 2], [4, 5], [7, 9, 10, 8]]
This solution has the advantage of being adaptable to more than 3 lists/intervals by adding more "pole" numbers.
EDIT: There's a nice & fast solution (O(log(N)*N)) if the output lists order don't matter:
first sort the input list
then generate the sliced sub-lists using bisect which returns insertion position of the provided numbers (left & right)
like this:
import bisect
source = sorted([1, 4, 7, 9, 2, 10, 5, 8])
poles = (0,3,6,25)
output = [source[bisect.bisect_left(source,poles[i]):bisect.bisect_right(source,poles[i+1])] for i in range(len(poles)-1)]
print(output)
result:
[[1, 2], [4, 5], [7, 8, 9, 10]]
You can do that in a very simple way using a combination of a for loop and range functions:
lists = ([], [], [])
for element in [1, 4, 7, 9, 2, 10, 5, 8]:
if element in range(0, 3):
lists[0].append(element)
elif element in range(3, 6):
lists[1].append(element)
elif element in range(6, 25):
lists[2].append(element)
array1, array2, array3 = lists
"One-line" solution using set.intersection(*others) and range(start, stop[, step]) functions:
l = [1, 4, 7, 9, 2, 10, 5, 8]
l1, l2, l3 = (list(set(l).intersection(range(3))), list(set(l).intersection(range(3,6))), list(set(l).intersection(range(6,25))))
print(l1)
print(l2)
print(l3)
The output:
[1, 2]
[4, 5]
[8, 9, 10, 7]
https://docs.python.org/3/library/stdtypes.html?highlight=intersection#set.intersection

python get last 5 elements in list of lists

I have a list of lists like this: [[1, 2], [4, 5, 6], [], None, [7, 12, 14, 16]].
I want to write a function that will return: [16, 14, 12, 7, 6]: i.e. the last 5 elements in the list of lists.
This is the code I have, but it is not very pythonic at all (master_list contains the list above):
def find_last_five():
last_five = []
limit = 5
for sublist in reversed(master_list):
# have to check that list is not None.
if sublist:
for elem in sublist:
last_five.append(elem)
limit -= 1
if (limit == 0):
return last_five
return last_five
import itertools as it
a = [[1, 2], [4, 5, 6], [], [7, 12, 14, 16]]
reversed(it.islice(it.chain.from_iterable(reversed(a)), 5))
That actually assumes there are no None's in a. If there are just do a = filter(a, None).
Given your example; I will assume your items in your list are either an iterable or None;
>>> import itertools
>>> lst = [[1, 2], [4, 5, 6], [], None, [7, 12, 14, 16]]
>>> print list(itertools.chain(*[l for l in lst if l is not None]))[-5:]
[6, 7, 12, 14, 16]
You can use a list comprehension:
>>> tgt=[[1, 2], [4, 5, 6], [], None, [7, 12, 14, 16]]
>>> [e for sub in tgt if sub for e in sub][-5:]
[6, 7, 12, 14, 16]
That filters out the None. To filter out other non-list or tuples:
>>> [e for sub in tgt if isinstance(sub, (list, tuple)) for e in sub][-5:]
If you want something that does not have to flatten the entire list of lists first, you can just deal with the structure from the end and move up until you have what you want:
result=[]
current=[]
it=reversed(tgt)
while len(result)<5:
if current:
result.append(current.pop())
continue
else:
try:
current=next(it)
except StopIteration:
break
(Or use John 1024's solution)
Using no external modules:
master = [[1, 2], [4, 5, 6], [], None, [7, 12, 14, 16]]
new = []
total = 5
for x in reversed(master):
if x:
new += list(reversed(x))[:total-len(new)]
if total == len(new):
break
print(new)
This produces:
[16, 14, 12, 7, 6]
which is the desired list with the elements in the desired order.
Alternative approach using flatten recipe:
import collections
l = [[1, 2], [4, 5, 6], [], None, [7, 12, 14, 16]]
def flatten(l):
for el in l:
if isinstance(el, collections.Iterable) and not isinstance(el, str):
for sub in flatten(el):
yield sub
else:
yield el
print([v for v in flatten(l) if v][-5:])
# gives: [6, 7, 12, 14, 16]
How about a different approach?
a = [[1, 2], [4, 5, 6], [], None, [7, 12, 14, 16]]
sum(filter(None, a), [])[-1:-6:-1]
The filter function is necessary only because of the None type in the list. In case it is just a list of lists, this will be lot simpler to write like this:
sum(a, [])[-1:-6:-1]
The principle behind this? We actually use the '+' operator of list to just keep on adding the lists into a single list. Please note that this is not the way to choose(if you choose ;)) for longer lists. For smaller and medium lists, this is fine.
I'd use itertools to do this. Something like
list(itertools.chain.from_iterable(x for x in l if x is not None))[:-5]
where l is your input list.

Python: Building a list comprehension that grows a list

I want to write some python that will take an existing list, and create a new list containing two entries for every entry in the original.
Example: Every entry should produce two new entries: x+1, and 3x.
a = [1]
a = [2, 3]
a = [3, 6, 4, 9]
a = [4, 9, 7, 18, 5, 12, 10, 27]
What code could be entered to produce the desired output:
a = [1]
for i in range(3):
a = ???
I have tried:
a = [(x+1, 3*x) for x in a]
... but this was incorrect because the first iteration gives a list containing a single tuple:
a = [(2, 3)]
... and a subsequent iteration does not work.
In addition to the answer, some explanation into the thought process that produces the answer would be most helpful.
EDIT: If anyone can give me some insight as to why my question is receiving close votes, I would appreciate that as well.
Here is a pretty efficient solution that uses itertools.chain.from_iterable and a generator expression:
>>> from itertools import chain
>>> a = [1]
>>> list(chain.from_iterable((x+1, x*3) for x in a))
[2, 3]
>>> a = [2, 3]
>>> list(chain.from_iterable((x+1, x*3) for x in a))
[3, 6, 4, 9]
>>> a = [3, 6, 4, 9]
>>> list(chain.from_iterable((x+1, x*3) for x in a))
[4, 9, 7, 18, 5, 12, 10, 27]
>>>
The links provided should explain everything except the list(...) part. I did that so the results were lists and not something like <itertools.chain object at 0x01815370>.
Edit in response to comment:
Yes, you can chain as many chain objects as you want and then convert the whole thing to a list in the end. See a demonstration below:
>>> a = [3, 6, 4, 9]
>>> list(chain.from_iterable((chain.from_iterable((x+1, x*3) for x in a), chain.from_iterable((x+1, x*3) for x in a))))
[4, 9, 7, 18, 5, 12, 10, 27, 4, 9, 7, 18, 5, 12, 10, 27]
>>>
def somefunc(n):
if not n:
return [1]
else:
return list(itertools.chain.from_iterable([(i+1, 3*i) for i in somefunc(n-1)]))
Output:
In [20]: somefunc(3)
Out[20]: [4, 9, 7, 18, 5, 12, 10, 27]
In [21]: somefunc(2)
Out[21]: [3, 6, 4, 9]
In [22]: somefunc(1)
Out[22]: [2, 3]

Categories

Resources