How to merge multiple lists? [duplicate] - python

This question already has answers here:
How do I make a flat list out of a list of lists?
(34 answers)
Closed 6 months ago.
I already know that if we have a list of two tuples like:
list = (('2', '23', '29', '26'), ('36', '0'))
by the below command:
new_list = list[0] + list[1]
it would be;
list = ('2', '23', '29', '26', '36', '0')
What shall I do if we have a plenty of tuples the below, and I want to use something like loop command?
list = [[list], [list2], [list3], ...]
I want:
new_list = [list1, list2, list3,...]

Use itertools.chain, and you can simply supply the list as arguments using * to expand them.
>>> from itertools import chain
>>> a_list = [[1], [2], [3]]
>>> list(chain(*a_list))
[1, 2, 3]
>>> tuple(chain(*a_list))
(1, 2, 3)
Also do not use pre-defined types such as list as a variable name as this redefines them to not being what they really are, and the parentheses (1, 2...) syntax results in a tuple, not a list.

Firstly, you are not merging two lists as you say in the question.
What you're doing is making a list of list into a list.
There are many ways you can do this. Apart from the ways listed in other answers, one possible solution could be:
for i in range(0, len(list_of_list)):
item = list_of_list[i]
for j in range(0,len(item)):
new_list = new_list + [item]
Note: This solution is typically labelled as C - like as it doesn't make use of any Python methods.

>>> main_list = [[1,2,3],[4,5,6,7],[8,9]]
>>> [item for sublist in main_list for item in sublist]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
This uses a nested list comprehension approach. A good explanation of how to read them can be found here.
Think how you'd do it with regular loops. One outer loop will extract a list and an inner loop will append every element of the list to the result.
>>> newlist = []
>>> for sublist in main_list:
for item in sublist:
newlist.append(item)
>>> newlist
[1, 2, 3, 4, 5, 6, 7, 8, 9]
Similarly, in the nested list comprehension above - the for sublist in main_list extracts a sublist, the for item in sublist loops over each item and the item at the beginning of the comprehension does an automatic list.append(item) to the final result. The biggest difference from regular loops is that what you want to get automatically appended to the final result is placed at the beginning.

Using sum() ,
>>> tp = ( ('2', '23', '29', '26'), ('36', '0'), ('4', '2') )
>>> newtp = sum(tp, () )
>>> newtp
('2', '23', '29', '26', '36', '0', '4', '2')
or itertools ,
>>> from itertools import chain
>>> tp = ( ('2', '23', '29', '26'), ('36', '0'), ('4', '2') )
>>> newtp = tuple( chain(*tp) )
>>> newtp
('2', '23', '29', '26', '36', '0', '4', '2')
or comprehension,
>>> tp = ( ('2', '23', '29', '26'), ('36', '0'), ('4', '2') )
>>> newtp = tuple(i for subtp in tp for i in subtp)
>>> newtp
('2', '23', '29', '26', '36', '0', '4', '2')

One simple way is using reduce inbuilt method.
>>> list_vals = (('2', '23', '29', '26'), ('36', '0'))
>>> reduce(lambda x, y: x + y, list_vals)
('2', '23', '29', '26', '36', '0')

In this case, all the entries of the list are integers and so it would be easy to use regular expressions. The extra advantage of using regular expressions here is that it will work on any arbitrary nested list vs. chain that does not work when the list is more than 1 degree nested.
import re
alist = [[1], [2],[3]]
results = [int(i) for i in re.findall('\d+', (str(alist)))]
print(results)
The output is;
>>> [1,2,4]
So if we are given an ugly arbitrarily nested list like:
a_list = [[1], [2], [3], [1,2,3[2,4,4], [0]], [8,3]]
we can do;
a_list = [[1], [2], [3], [1,2,3, [2,4,4], [0]], [8,3]]
results = [int(i) for i in re.findall('\d+', (str(a_list)))]
print(results)
and the output is;
>>> [1, 2, 3, 1, 2, 3, 2, 4, 4, 0, 8, 3]
Which is arguably more helpful.

Related

Remove duplicates from a nested list

I have a list
A = [['1'],['1','2'],['1','2','3','1','2'],['3','3','3']]
and I want to make my list to
A = [['1'],['1','2'],['1','2','3'],['3']]
ie I want to remove duplicate elements within the elements in a list ..
One-liner (If order doesn't matter) :
A = [['1'],['1','2'],['1','2','3','1','2'],['3','3','3']]
A = [list(set(a)) for a in A]
print(A) # => [['1'], ['2', '1'], ['3', '2', '1'], ['3']]
One-liner (If order matters) :
A = [['1'],['1','2'],['1','2','3','1','2'],['3','3','3']]
A = [sorted(set(a), key=a.index) for a in A]
print(A) # => [['1'], ['1', '2'], ['1', '2', '3'], ['3']]
A functional version, with functools:
>>> import functools
>>> A = [['1'],['1','2'],['1','2','3','1','2'],['3','3','3']]
>>> print ([functools.reduce(lambda result,x:result if x in result else result+[x], xs, []) for xs in A])
[['1'], ['1', '2'], ['1', '2', '3'], ['3']]
The lambda function adds an element to the result list only if that element is not present in the list. Not very efficient, but keeps the order of elements.
Also note that with Python 2, you don't need to import functools: reduce is a builtin function.
You can use a generator:
def remove_dups(l):
for a in l:
new_l = []
for b in a:
if b not in new_l:
new_l.append(b)
yield new_l
A = [['1'],['1','2'],['1','2','3','1','2'],['3','3','3']]
print(list(remove_dups(A)))
Output:
[['1'], ['1', '2'], ['1', '2', '3'], ['3']]

How to create lists from every item of an existing list in python 2.7.11?

I am trying to generate lists from the elements of a list in python.
For example: there is a list with the following information:
list=['AB4', 'AB3','AC3', 'BC4', 'BC5']
This is the exact format of the elements of the list.
I suppouse to create list for every element, separate for the letters (considering both letters as one block) and separate for the numbers, that will contain the missing character from their string. Here is what I mean:
AB:['4', '3']
AC:['3']
BC:['4', '5']
4:['AB', 'BC']
3:['AB', 'AC']
5:['BC']
These are the lists that I should generate from the original list. There is no limitation to the elements of the original list, and their format is exactly like in the example "two letters and a number".
Thank you in advance.
You can use regexes (the re module) and a defaultdict to accomplish this. The following will work for arbitrary lengths of the non-digit/digit parts of your input strings:
import re
from collections import defaultdict
def str_dig(s): # str_dig('ABC345') -> ('ABC', '345')
return re.match('([^\d]+)(\d+)', s).groups()
lst=['AB4', 'AB3','AC3', 'BC4', 'BC5'] # do NOT shadow list!
d = defaultdict(list)
for x, y in map(str_dig, lst): # map applies the str_dig function to all in lst
d[x].append(y)
d[y].append(x)
# d['AB']: ['4', '3'], d['3']: ['AB', 'AC']
This will do it:
from collections import defaultdict
l=['AB4', 'AB3','AC3', 'BC4', 'BC5']
result=defaultdict(list)
for item in l:
#If you want numbers to be numbers and not strings replace item[2:] with int(item[2:])
result[item[:2]].append(item[2:])
result[item[2:]].append(item[:2])
And you can use this to print it just as you want:
import pprint
pp = pprint.PrettyPrinter()
pp.pprint(result)
output:
{'3': ['AB', 'AC'],
'4': ['AB', 'BC'],
'5': ['BC'],
'AB': ['4', '3'],
'AC': ['3'],
'BC': ['4', '5']}
How about this,
import itertools
import operator
l = ['AB4', 'AB3','AC3', 'BC4', 'BC5']
lists = [(s[:2], s[2]) for s in l] # [('AB', '4'), ('AB', '3'), ('AC', '3'), ('BC', '4'), ('BC', '5')]
results = dict()
for name, group in itertools.groupby(sorted(lists, key=operator.itemgetter(0)), key=operator.itemgetter(0)):
results[name] = map(operator.itemgetter(1), group)
for name, group in itertools.groupby(sorted(lists, key=operator.itemgetter(1)), key=operator.itemgetter(1)):
results[name] = map(operator.itemgetter(0), group)
print(results)
# Output
{ 'AC': ['3'],
'AB': ['4', '3'],
'BC': ['4', '5'],
'3': ['AB', 'AC'],
'5': ['BC'],
'4': ['AB', 'BC']}

How can i sort the list with keys in python

I have the two list dictionary like this
obj1 = [mydict['obj1'],mydict['obj2'],mydict['obj3'],mydict['obj4']]
obj2 = [mydict['obj1'],mydict['obj2'],mydict['obj3'],mydict['obj4'], mydict['obj5'] ]
Now i want that
Count the number of elements in each list
Then based on whichever is greater then get that list of objects
I want a single list which conatins the above two list of(list of) dictionaries based on the higher number of elements so that i cause something like this
mylist = myfunc(objects1, objects2 )
mylist should be a list like [objects1, objects2] depending upon who has greater number of objects.
what is the best way to do that with less lines of code
Something like EDIT
mylist = sorted([obj1, obj2], key=lambda a: len(a), reverse=True)
There's no need to use a lambda function if it's just going to call a function anyway.
>>> objects1 = [1, 2, 3]
>>> objects2 = ['1', '2', '3', '4']
>>>
>>> mylist = [objects1, objects2]
>>> max(mylist, key=len)
['1', '2', '3', '4']
>>> sorted(mylist, key=len, reverse=True)
[['1', '2', '3', '4'], [1, 2, 3]]
objects1 = [1, 2, 3]
objects2 = ['1', '2', '3', '4']
mylist = [objects1, objects2]
mylist.sort(key=len, reverse=True)
print mylist
[['1', '2', '3', '4'], [1, 2, 3]]

Grouping lists within lists in Python 3

I have a list of lists of strings like so:
List1 = [
['John', 'Doe'],
['1','2','3'],
['Henry', 'Doe'],
['4','5','6']
]
That I would like to turn into something like this:
List1 = [
[ ['John', 'Doe'], ['1','2','3'] ],
[ ['Henry', 'Doe'], ['4','5','6'] ]
]
But I seem to be having trouble doing so.
List1 = [['John', 'Doe'], ['1','2','3'],
['Henry', 'Doe'], ['4','5','6'],
['Bob', 'Opoto'], ['10','11','12']]
def pairing(iterable):
it = iter(iterable)
itn = it.next
for x in it :
yield (x,itn())
# The generator pairing(iterable) yields tuples:
for tu in pairing(List1):
print tu
# produces:
(['John', 'Doe'], ['1', '2', '3'])
(['Henry', 'Doe'], ['4', '5', '6'])
(['Bob', 'Opoto'], ['8', '9', '10'])
# If you really want a yielding of lists:
from itertools import imap
# In Python 2. In Python 3, map is a generator
for li in imap(list,pairing(List1)):
print li
# or defining pairing() precisely so:
def pairing(iterable):
it = iter(iterable)
itn = it.next
for x in it :
yield [x,itn()]
# produce
[['John', 'Doe'], ['1', '2', '3']]
[['Henry', 'Doe'], ['4', '5', '6']]
[['Bob', 'Opoto'], ['8', '9', '10']]
Edit: Defining a generator function isn't required, you can do the pairing of a list on the fly:
List1 = [['John', 'Doe'], ['1','2','3'],
['Henry', 'Doe'], ['4','5','6'],
['Bob', 'Opoto'], ['8','9','10']]
it = iter(List1)
itn = it.next
List1 = [ [x,itn()] for x in it]
This should do what you want assuming you always want to take pairs of the inner lists together.
list1 = [['John', 'Doe'], ['1','2','3'], ['Henry', 'Doe'], ['4','5','6']]
output = [list(pair) for pair in zip(list1[::2], list1[1::2])]
It uses zip, which gives you tuples, but if you need it exactly as you've shown, in lists, the outer list comprehension does that.
Here it is in 8 lines. I used tuples rather than lists because it's the "correct" thing to do:
def pairUp(iterable):
"""
[1,2,3,4,5,6] -> [(1,2),(3,4),(5,6)]
"""
sequence = iter(iterable)
for a in sequence:
try:
b = next(sequence)
except StopIteration:
raise Exception('tried to pair-up %s, but has odd number of items' % str(iterable))
yield (a,b)
Demo:
>>> list(pairUp(range(0)))
[]
>>> list(pairUp(range(1)))
Exception: tried to pair-up [0], but has odd number of items
>>> list(pairUp(range(2)))
[(0, 1)]
>>> list(pairUp(range(3)))
Exception: tried to pair-up [0, 1, 2], but has odd number of items
>>> list(pairUp(range(4)))
[(0, 1), (2, 3)]
>>> list(pairUp(range(5)))
Exception: tried to pair-up [0, 1, 2, 3, 4], but has odd number of items
Concise method:
zip(sequence[::2], sequence[1::2])
# does not check for odd number of elements

How can I find the locations of an item in a Python list of lists?

I want to find the location(s) of a specific item in a list of lists. It should return a list of tuples, where each tuple represents the indexes for a specific instance of the item. For example:
list = [['1', '2', '4', '6'], ['7', '0', '1', '4']]
getPosition('1') #returns [(0, 0), (1, 2)]
and getPosition('7') #returns [(1,0)]
If you want something that will both
find duplicates and
handle nested lists (lists of lists of lists of ...)
you can do something like the following:
def get_positions(xs, item):
if isinstance(xs, list):
for i, it in enumerate(xs):
for pos in get_positions(it, item):
yield (i,) + pos
elif xs == item:
yield ()
Testing this:
>>> xs = [['1', '2', '4', '6'],
... ['7', '0', '1', '4'],
... [ [ '0', '1', '1'], ['1']]
... ]
>>> print list(get_positions(xs, '1'))
[(0, 0), (1, 2), (2, 0, 1), (2, 0, 2), (2, 1, 0)]
It looks likes you want, for a list of sublists and a given item, to return a list of pairs where each pair is (the index of the sublist, the index of the item within the sublist). You can do that using list comprehensions and Python's built in enumerate() function:
def getPosition(list, item):
return [(i, sublist.index(item)) for i, sublist in enumerate(list)]
Edit: See #scribble's answer above/below.
def getPosition(list, item):
return [(i, sublist.index(item)) for i, sublist in enumerate(list)
if item in sublist]
def get_positions(xs, target):
return [(i,e.index(target)) for i,e in enumerate(xs)]
That's a good starting point. Presumably you have some sort of class such as
class SomeClass:
def __init__(self):
self.xs = [['1','2','4','6'], ['7','0','1','4']]
def get_positions(self, target):
return [(i,e.index(target)) for i,e in enumerate(self.xs)]
which in this case would let you say
model = SomeClass()
model.get_position(1) # returns [(0,0), (1,2)]
Note that in both cases you'll get an exception if your target isn't in every one of your sublists. The question does not specify whether this is the desired behavior.
If you don't want a exception if the item is not in the list try this. Also as a generator because they are cool and versatile.
xs = [['1', '2', '4', '6'], ['7', '0', '1', '4']]
def get_positions(xs, item):
for i, xt in enumerate( xs ):
try: # trying beats checking
yield (i, xt.index(item))
except ValueError:
pass
print list(get_positions(xs, '1'))
print list(get_positions(xs, '6'))
# Edit for fun: The one-line version, without try:
get_positions2 = lambda xs,item: ((i,xt.index(item)) for i, xt in enumerate(xs) if item in xt)
print list(get_positions2(xs, '1'))
print list(get_positions2(xs, '6'))
A while ago I wrote a library for python to do list matching that would fit the bill pretty well. It used the tokens ?, +, and * as wildcards, where ? signifies a single atom, + is a non-greedy one-or-more, and * is greedy one-or-more. For example:
from matching import match
match(['?', 2, 3, '*'], [1, 2, 3, 4, 5])
=> [1, [4, 5]]
match([1, 2, 3], [1, 2, 4])
=> MatchError: broken at 4
match([1, [2, 3, '*']], [1, [2, 3, 4]])
=> [[4]]
match([1, [2, 3, '*']], [1, [2, 3, 4]], True)
=> [1, 2, 3, [4]]
Download it here: http://www.artfulcode.net/wp-content/uploads/2008/12/matching.zip
Here is a version without try..except, returning an iterator and that for
[['1', '1', '1', '1'], ['7', '0', '4']]
returns
[(0, 0), (0, 1), (0, 2), (0, 3)]
def getPosition1(l, val):
for row_nb, r in enumerate(l):
for col_nb in (x for x in xrange(len(r)) if r[x] == val):
yield row_nb, col_nb
The most strainghtforward and probably the slowest way to do it would be:
>>> value = '1'
>>> l = [['1', '2', '3', '4'], ['3', '4', '5', '1']]
>>> m = []
>>> for i in range(len(l)):
... for j in range(len(l[i])):
... if l[i][j] == value:
... m.append((i,j))
...
>>> m
[(0, 0), (1, 3)]
Here is another straight forward method that doesn't use generators.
def getPosition(lists,item):
positions = []
for i,li in enumerate(lists):
j = -1
try:
while True:
j = li.index(item,j+1)
positions.append((i,j))
except ValueError:
pass
return positions
l = [['1', '2', '4', '6'], ['7', '0', '1', '4']]
getPosition(l,'1') #returns [(0, 0), (1, 2)]
getPosition(l,'9') # returns []
l = [['1', '1', '1', '1'], ['7', '0', '1', '4']]
getPosition(l,'1') #returns [(0, 0), (0, 1), (0,2), (0,3), (1,2)]

Categories

Resources