Arranging nested lists in python - python

Consider the following list in python:
[[[1, 2], [3, 4], [5, 6], [7, 8]],
[['a', 'b'], ['c', 'd'], ['e', 'f'], ['g', 'h']],
[[21, 22], [23, 24], [25, 26], [27, 28]]]
The top level list contains 3 list values which in-turn consists of 4 individual lists.
I need to arrange these this lists in the following order:
[[1, 2, 'a', 'b', 21, 22],
[3, 4, 'c', 'd', 23, 24],
[5, 6, 'e', 'f', 25, 26],
[7, 8, 'g', 'h', 27, 28]]
I have tried to implement this requirement using itertools, for loops, list comprehension etc but was unable to get it. Could you provide me the necessary python code capable of doing this requirement?

You need to use zip() here, then flatten out the resulting tuples with sublists:
[[i for sub in combo for i in sub] for combo in zip(*inputlist)]
Demo:
>>> inputlist = [[[1, 2], [3, 4], [5, 6], [7, 8]],
... [['a', 'b'], ['c', 'd'], ['e', 'f'], ['g', 'h']],
... [[21, 22], [23, 24], [25, 26], [27, 28]]]
>>> [[i for sub in combo for i in sub] for combo in zip(*inputlist)]
[[1, 2, 'a', 'b', 21, 22], [3, 4, 'c', 'd', 23, 24], [5, 6, 'e', 'f', 25, 26], [7, 8, 'g', 'h', 27, 28]]

Using itertools with map:
>>> from itertools import chain, izip, starmap
>>> map(list, starmap(chain, izip(*lst)))
[[1, 2, 'a', 'b', 21, 22],
[3, 4, 'c', 'd', 23, 24],
[5, 6, 'e', 'f', 25, 26],
[7, 8, 'g', 'h', 27, 28]]

Related

How to interchange the values in a list of lists?

I have a list of lists. I need to interchange the values inside each one.
For example: ['a', 12] to [12, 'a']
Input:
x = [['a', 12],
['b', 14],
['c', 22],
['d', 29],
['e', 29],
['f', 29],
['g', 29],
['h', 30],
['i', 2],
['j', 8]]
My expected output:
y = [[12, 'a'],
[14, 'b'],
[22, 'c'],
[29, 'd'],
[29, 'e'],
[29, 'f'],
[29, 'g'],
[30, 'h'],
[2, 'i'],
[8, 'j']]
[i[::-1] for i in list_change]
Here you go :
list_change = [['a', 12],['b', 14],['c', 22],['d', 29]]
new_list_change = [[sublist[1], sublist[0]] for sublist in list_change]
lst = [['a', 12], ['b', 14], ['c', 22], ['d', 29]]
print([[item[1], item[0]] for item in lst])
[[num, let] for let, num in list_change]
In the following solution the lists are not reconstructed. The data are changed "in place". This may be wanted or unwanted if any other variable is pointing to one of the small lists in the list.
for i in range(len(mylist)):
a, b = mylist[i]
mylist[i][:] = b, a
If you want to leave everything in place, but generate a new list with swapped elements, use r.ook's answer or—if you think that list comprehension is hard to read—this:
newlist = []
for a, b in oldlist:
newlist.append([b, a])

Create dict using a grouping column in an array and assigning the remaining columns to values of the dict

I have a type(s1) = numpy.ndarray. I want to create a dictionary by using the first column of s1 as key and rest as values to the key. The first column has repeated values.
Here is np.array.
s1 = np.array([[1L, 'R', 4],
[1L, 'D', 3],
[1L, 'I', 10],
[1L, 'K', 0.0],
[2L, 'R', 11],
[2L, 'D', 13],
[2L, 'I', 1],
[2L, 'K', 6],
[3L, 'R', 12],
[3L, 'D', 17],
[3L, 'I', 23],
[3L, 'K', 10]], dtype=object)
I want to get the following:
{'1':[['R',4],['D',3],['I',10],['K',0]],
'2':[['R',11],['D',13],['I',1],['K',6]],
'3':[['R',12],['D',17],['I',23],['K',10]]}
This is what I tried and got:
In [18]: {x[0]:[x[1],x[2]] for x in s1}
Out[18]: {1L: ['K', 0.0], 2L: ['D', 6], 3L: ['K', 10]}
I see the problem that the grouping column has repeated values. But I am unable to do the appending. What is the trick I am missing?
You can simply built them with defaultdict :
d=collections.defaultdict(list)
for k,*v in s1 : d[k].append(list(v))
for
defaultdict(list,
{1: [['R', 4], ['D', 3], ['I', 10], ['K', 0.0]],
2: [['R', 11], ['D', 13], ['I', 1], ['K', 6]],
3: [['R', 12], ['D', 17], ['I', 23], ['K', 10]]})
EDIT
You can nest dicts in dicts :
d=collections.defaultdict(dict)
for k1,k2,v in s1 : d[k1][k2]=v
#defaultdict(dict,
# {1: {'D': 3, 'I': 10, 'K': 0.0, 'R': 4},
# 2: {'D': 13, 'I': 1, 'K': 6, 'R': 11},
# 3: {'D': 17, 'I': 23, 'K': 10, 'R': 12}})
In [67]: d[2]['K']
Out[67]: 6
See here for generalization.
You might want to use itertools.groupby():
In [15]: {k: [list(x[1:]) for x in g]
....: for k,g in itertools.groupby(s1, key=lambda x: x[0])}
Out[15]:
{1L: [['R', 4], ['D', 3], ['I', 10], ['K', 0.0]],
2L: [['R', 11], ['D', 13], ['I', 1], ['K', 6]],
3L: [['R', 12], ['D', 17], ['I', 23], ['K', 10]]}

Merge function will only work for ordered list

I have this 2 lists as input:
list1 = [['A', 14, 'I', 10, 20], ['B', 15, 'S', 30, 40], ['C', 16, 'F', 50, 60]]
list2 = [['A', 14, 'Y', 0, 200], ['B', 15, 'M', 0, 400], ['C', 17, 'G', 0, 600]]
and my desired output will be this:
finalList = [['A', 14, 'Y', 10, 200], ['B', 15, 'M', 30, 400], ['C', 16, 'F', 50, 60],['C', 17, 'G', 0, 600]]
Using this function:
def custom_merge(list1, list2):
finalList = []
for sub1, sub2 in zip(list1, list2):
if sub1[1]==sub2[1]:
out = sub1.copy()
out[2] = sub2[2]
out[4] = sub2[4]
finalList.append(out)
else:
finalList.append(sub1)
finalList.append(sub2)
return finalList
I will get indeed my desired output, but what if I switch positions (list2[1] and list2[2]) and my list2:
list2 = [['A', 14, 'Y', 0, 200], ['C', 17, 'G', 0, 600], ['B', 15, 'M', 0, 400]]
Then the output will be this:
[['A', 14, 'Y', 10, 200], ['B', 15, 'S', 30, 40], ['C', 17, 'G', 0, 600], ['C', 16, 'F', 50, 60], ['B', 15, 'M', 0, 400]]
(notice the extra ['B', 15, 'M', 0, 400])
What I have to modify in my function in order to get my first desired output if my lists have a different order in my list of lists!? I use python 3. Thank you!
LATER EDIT:
Merge rules:
When list1[listindex][1] == list2[listindex][1] (ex: when 14==14), replace in list1 -> list2[2] and list2[4] (ex: 'Y' and 200) and if not just add the unmatched list from list2 to list1 as it is (like in my desired output) and also keep the ones that are in list1 that aren't matched(ex: ['C', 16, 'F', 50, 60])
To be noted that list1 and list2 can have different len (list1 can have more lists than list2 or vice versa)
EDIT.2
I found this:
def combine(list1,list2):
combined_list = list1 + list2
final_dict = {tuple(i[:2]):tuple(i[2:]) for i in combined_list}
merged_list = [list(k) + list (final_dict[k]) for k in final_dict]
return merged_list
^^ That could work, still testing!
You can sort the lists by the first element in the sublists before merging them.
def custom_merge(list1, list2):
finalList = []
for sub1, sub2 in zip(sorted(list1), sorted(list2)):
if sub1[1]==sub2[1]:
out = sub1.copy()
out[2] = sub2[2]
out[4] = sub2[4]
finalList.append(out)
else:
finalList.append(sub1)
finalList.append(sub2)
return finalList
tests:
list1 = [['A', 14, 'I', 10, 20], ['B', 15, 'S', 30, 40], ['C', 16, 'F', 50, 60]]
list2 = [['A', 14, 'Y', 0, 200], ['C', 17, 'G', 0, 600], ['B', 15, 'M', 0, 400]]
custom_merge(list1, list2)
# returns:
[['A', 14, 'Y', 10, 200],
['B', 15, 'M', 30, 400],
['C', 16, 'F', 50, 60],
['C', 17, 'G', 0, 600]]

Slicing flat list into multi-level nested list efficiently

For example, I have a flat list
[1, 2, 3, 4, 5, 6, 7, 8, 9, 'A', 'B', 'C', 'D', 'E', 'F', 'G']
I want to transform it into 4-deep list
[[[[1, 2], [3, 4]], [[5, 6], [7, 8]]], [[[9, 'A'], ['B', 'C']], [['D', 'E'] ['F', 'G']]]]
Is there a way to do it without creating a separate variable for every level? What is the most memory- and performance-efficient way?
UPDATE:
Also, is there a way to do it in a non-symmetrical fashion?
[[[[1, 2, 3], 4], [[5, 6, 7], 8]]], [[[9, 'A', 'B'], 'C']], [['D', 'E', 'F'], 'G']]]]
Note that your first list has 15 elements instead of 16. Also, what should A be? Is it a constant you've defined somewhere else? I'll just assume it's a string : 'A'.
If you work with np.arrays, you could simply reshape your array:
import numpy as np
r = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 'A', 'B', 'C', 'D', 'E', 'F', 'G'])
r.reshape(2,2,2,2)
It outputs:
array([[[['1', '2'],
['3', '4']],
[['5', '6'],
['7', '8']]]
[[['9', 'A'],
['B', 'C']],
[['D', 'E'],
['F', 'G']]]
dtype='<U11')
This should be really efficient because numpy doesn't change the underlying data format. It's still a flat array, displayed differently.
Numpy doesn't support irregular shapes. You'll have to work with standard python lists then:
i = iter([1, 2, 3, 4, 5, 6, 7, 8, 9, 'A', 'B', 'C', 'D', 'E', 'F', 'G'])
l1 = []
for _ in range(2):
l2 = []
for _ in range(2):
l3 = []
l4 = []
for _ in range(3):
l4.append(next(i))
l3.append(l4)
l3.append(next(i))
l2.append(l3)
l1.append(l2)
print(l1)
# [[[[1, 2, 3], 4], [[5, 6, 7], 8]], [[[9, 'A', 'B'], 'C'], [['D', 'E', 'F'], 'G']]]
As you said, you'll have to define a temporary variable for each level. I guess you could use list comprehensions, but they wouldn't be pretty.

Organize list of lists in Python

Let's say a have a list of lists in Python:
list_of_values = [[a, b, c], [d, e, f], [g, h, i], [j, k, l]]
And I want to convert automatically to independent lists like:
list1 = [[a, b, c],[d + g + j, e + h + k, f + i + l]]
list2 = [[d, e, f], [g + j, h + k, i + l]]
list3 = [[g, h, i], [j, k, l]]
Let's say I have a list of lists of integers in Python:
list_of_values = [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]
And I want to convert automatically to independent lists like:
list1 = [[1, 2, 3],[4 + 7 + 10, 5 + 8 + 11, 6 + 9 + l2]]
list2 = [[4, 5, 6], [7 + 10, 8 + 11, 9 + 12]]
list3 = [[7, 8, 9], [10, 11, l2]]
Performing the math:
list1 = [[1, 2, 3], [21, 24, 27]]
list2 = [[4, 5, 6], [17, 19, 21]]
list3 = [[7, 8, 9], [10, 11, l2]]
For your updated Question:
Suppose you have "list of lists of strings" like below:
s = [['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'i'], ['j', 'k', 'l']]
Then you can use: join to concatenate:
>>> for i in range(len(s)):
... [s[i], map(lambda t: ''.join(t), zip(*s[i + 1:]))]
...
[['a', 'b', 'c'], ['dgj', 'ehk', 'fil']]
[['d', 'e', 'f'], ['gj', 'hk', 'il']]
[['g', 'h', 'i'], ['j', 'k', 'l']]
[['j', 'k', 'l'], []]
If you don't need last line in output then just use range argument less then one of length:
>>> for i in range(len(s)-1):
... [s[i], map(''.join, zip(*s[i + 1:]))] # remove lambda function
...
[['a', 'b', 'c'], ['dgj', 'ehk', 'fil']]
[['d', 'e', 'f'], ['gj', 'hk', 'il']]
[['g', 'h', 'i'], ['j', 'k', 'l']]
But suppose if you have "list of lists of numbers" e.g.:
l = [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]
Then you can use sum function:
>>> for i in range(len(l) - 1):
... [l[i], map(sum, zip(*l[i + 1:]))]
...
[[1, 2, 3], [21, 24, 27]]
[[4, 5, 6], [17, 19, 21]]
[[7, 8, 9], [10, 11, 12]]
Edit:..
If you wants to make single function for both strings and number then you canmake use of add() operator from operator library.
Check add() function:
>>> from operator import add
>>> add(1, 2)
3
>>> add('1', '2') # this is like + works
'12'
Now, using it make a new my_add() that add all elements in a sequence, check following codes:
>>> def my_add(t):
... return reduce(add, t)
...
>>> my_add(('a', 'b'))
'ab'
>>> my_add((2, 1))
3
Now, write a function using my_add() function that will so your work:
def do_my_work(s):
for i in range(len(s)-1):
print [s[i], map(my_add, zip(*s[i + 1:]))]
Now, see how this works for you:
>>> s
[['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'i'], ['j', 'k', 'l']]
>>> do_my_work(s)
[['a', 'b', 'c'], ['dgj', 'ehk', 'fil']]
[['d', 'e', 'f'], ['gj', 'hk', 'il']]
[['g', 'h', 'i'], ['j', 'k', 'l']]
>>> l
[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]
>>> do_my_work(l) # so same function for str and int both!
[[1, 2, 3], [21, 24, 27]]
[[4, 5, 6], [17, 19, 21]]
[[7, 8, 9], [10, 11, 12]]
>>> import itertools
>>> lst = [['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'i'], ['j', 'k', 'l']]
>>> for i, item in enumerate(lst):
print [item, itertools.chain.from_iterable(lst[i+1:])]
[['a', 'b', 'c'], ['d', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l']]
[['d', 'e', 'f'], ['g', 'h', 'i', 'j', 'k', 'l']]
[['g', 'h', 'i'], ['j', 'k', 'l']]
[['j', 'k', 'l'], []]
for i in range(len(list_of_values) - 1):
print [list_of_values[i]] + [map(list, zip(*list_of_values[i+1:]))]
Output
[['a', 'b', 'c'], [['d', 'g', 'j'], ['e', 'h', 'k'], ['f', 'i', 'l']]]
[['d', 'e', 'f'], [['g', 'j'], ['h', 'k'], ['i', 'l']]]
[['g', 'h', 'i'], [['j'], ['k'], ['l']]]
For the numbers, you can simply do
list_of_values = [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]
for i in range(len(list_of_values) - 1):
print [list_of_values[i]] + [map(sum, zip(*list_of_values[i+1:]))]
Output
[[1, 2, 3], [21, 24, 27]]
[[4, 5, 6], [17, 19, 21]]
[[7, 8, 9], [10, 11, 12]]

Categories

Resources