Related
This question already has an answer here:
list extend() to index, inserting list elements not only to the end
(1 answer)
Closed last month.
In python we can add lists to each other with the extend() method but it adds the second list at the end of the first list.
lst1 = [1, 4, 5]
lst2 = [2, 3]
lst1.extend(lst2)
Output:
[1, 4, 5, 2, 3]
How would I add the second list to be apart of the 1st element? Such that the result is this;
[1, 2, 3, 4, 5 ]
I've tried using lst1.insert(1, *lst2) and got an error;
TypeError: insert expected 2 arguments, got 3
For those who don't like reading comments:
lst1 = [1, 4, 5]
lst2 = [2, 3]
lst1[1:1] = lst2
print(lst1)
Output:
[1, 2, 3, 4, 5]
If your only goal is to get the list sorted correctly, then you use .extend() and .sort() afterwards.
You can solve your problem in two steps:
Insert the list into the other list
Flatten the result
Code:
from collections.abc import Iterable
# https://stackoverflow.com/questions/2158395/flatten-an-irregular-arbitrarily-nested-list-of-lists
def flatten(xs):
for x in xs:
if isinstance(x, Iterable) and not isinstance(x, (str, bytes)):
yield from flatten(x)
else:
yield x
xs = [1,4,5]
ys = [2,3]
xs.insert(1, ys)
print("intermediate result", xs)
xs = flatten(xs)
print(xs)
From this list:
N = [1,2,2,3,3,3,4,4,4,4,5,5,5,5,5]
I'm trying to create:
L = [[1],[2,2],[3,3,3],[4,4,4,4],[5,5,5,5,5]]
Any value which is found to be the same is grouped into it's own sublist.
Here is my attempt so far, I'm thinking I should use a while loop?
global n
n = [1,2,2,3,3,3,4,4,4,4,5,5,5,5,5] #Sorted list
l = [] #Empty list to append values to
def compare(val):
""" This function receives index values
from the n list (n[0] etc) """
global valin
valin = val
global count
count = 0
for i in xrange(len(n)):
if valin == n[count]: # If the input value i.e. n[x] == n[iteration]
temp = valin, n[count]
l.append(temp) #append the values to a new list
count +=1
else:
count +=1
for x in xrange (len(n)):
compare(n[x]) #pass the n[x] to compare function
Use itertools.groupby:
from itertools import groupby
N = [1,2,2,3,3,3,4,4,4,4,5,5,5,5,5]
print([list(j) for i, j in groupby(N)])
Output:
[[1], [2, 2], [3, 3, 3], [4, 4, 4, 4], [5, 5, 5, 5, 5]]
Side note: Prevent from using global variable when you don't need to.
Someone mentions for N=[1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5, 1] it will get [[1], [2, 2], [3, 3, 3], [4, 4, 4, 4], [5, 5, 5, 5, 5], [1]]
In other words, when numbers of the list isn't in order or it is a mess list, it's not available.
So I have better answer to solve this problem.
from collections import Counter
N = [1,2,2,3,3,3,4,4,4,4,5,5,5,5,5]
C = Counter(N)
print [ [k,]*v for k,v in C.items()]
You can use itertools.groupby along with a list comprehension
>>> l = [1,2,2,3,3,3,4,4,4,4,5,5,5,5,5]
>>> [list(v) for k,v in itertools.groupby(l)]
[[1], [2, 2], [3, 3, 3], [4, 4, 4, 4], [5, 5, 5, 5, 5]]
This can be assigned to the variable L as in
L = [list(v) for k,v in itertools.groupby(l)]
You're overcomplicating this.
What you want to do is: for each value, if it's the same as the last value, just append it to the list of last values; otherwise, create a new list. You can translate that English directly to Python:
new_list = []
for value in old_list:
if new_list and new_list[-1][0] == value:
new_list[-1].append(value)
else:
new_list.append([value])
There are even simpler ways to do this if you're willing to get a bit more abstract, e.g., by using the grouping functions in itertools. But this should be easy to understand.
If you really need to do this with a while loop, you can translate any for loop into a while loop like this:
for value in iterable:
do_stuff(value)
iterator = iter(iterable)
while True:
try:
value = next(iterator)
except StopIteration:
break
do_stuff(value)
Or, if you know the iterable is a sequence, you can use a slightly simpler while loop:
index = 0
while index < len(sequence):
value = sequence[index]
do_stuff(value)
index += 1
But both of these make your code less readable, less Pythonic, more complicated, less efficient, easier to get wrong, etc.
You can do that using numpy too:
import numpy as np
N = np.array([1,2,2,3,3,3,4,4,4,4,5,5,5,5,5])
counter = np.arange(1, np.alen(N))
L = np.split(N, counter[N[1:]!=N[:-1]])
The advantage of this method is when you have another list which is related to N and you want to split it in the same way.
Another slightly different solution that doesn't rely on itertools:
#!/usr/bin/env python
def group(items):
"""
groups a sorted list of integers into sublists based on the integer key
"""
if len(items) == 0:
return []
grouped_items = []
prev_item, rest_items = items[0], items[1:]
subgroup = [prev_item]
for item in rest_items:
if item != prev_item:
grouped_items.append(subgroup)
subgroup = []
subgroup.append(item)
prev_item = item
grouped_items.append(subgroup)
return grouped_items
print group([1,2,2,3,3,3,4,4,4,4,5,5,5,5,5])
# [[1], [2, 2], [3, 3, 3], [4, 4, 4, 4], [5, 5, 5, 5, 5]]
Say I have a list:
l1 = [[1, 3], [3, 2], [2, 1]]
I want to push each item in l1 to a binary heap, 'memory' but sorted in the binary heap by each_item[-1].
I've tried: heapq.heappush(_heap, item=itemgetter(-1)) and the equivilent using an anonymous function but I get:
TypeError: heappush() takes no keyword arguments
You can store entries in the heap as 3-element tuples including the last element, an entry count, and the actual item. This way the items will be sorted by their last values with the entry count ensuring sort stability (i.e. two items with equal last elements are returned in the order they were added):
>>> import heapq
>>> heap = []
>>> l1 = [[1, 3], [3, 2], [2, 1]]
>>> for count, item in enumerate(l1):
... heapq.heappush(heap, (item[-1], count, item))
...
>>> while heap:
... print(heapq.heappop(heap)[-1])
...
[2, 1]
[3, 2]
[1, 3]
One option is to make small wrappers around heapq functions to prepend/extract the sorting value to/from the item in a consistent way:
def heappush(h, item, key=lambda x: x):
heapq.heappush(h, (key(item), item))
def heappop(h):
return heapq.heappop(h)[1]
def heapify(h, key=lambda x: x):
for idx, item in enumerate(h):
h[idx] = (key(item), item)
heapq.heapify(h)
Testing with your sample:
l1 = [[1, 3], [3, 2], [2, 1]]
h = []
for item in l1:
heappush(h, item, key=itemgetter(-1))
while h:
print(heappop(h))
Prints:
[2, 1]
[3, 2]
[1, 3]
Note that you could use h=l1; heapify(h, key=itemgetter(-1)) which should be faster than individually heappushing each item.
I like Eugene's solution but if working with this special tuple a lot, one could define a custom object to achieve this as follows:
from heapq import heappush, heappop
class MyTupleHeapObj(object):
def __init__(self,val): self.val = val
def __lt__(self,other): return self.val[-1] < other.val[-1]
def __eq__(self,other): return self.val == other.val
def __str__(self): return str(self.val)
h = []
for item in [[1, 3], [3, 2], [2, 1]]:
heappush(h, MyTupleHeapObj(item))
while h:
print heappop(h)
Prints the following:
[2, 1]
[3, 2]
[1, 3]
Given some matrix, I need to mirror all the rows in the matrix. For example
[[2, 1],
[4, 3]]
would become
[[1, 2],
[3, 4]]
I managed to do it for the (2 x 2)-case. But I'm having trouble mirroring something like this:
[[1, 2, 3, 4],
[1, 2, 3, 4]]
This has to become
[[4, 3, 2, 1],
[4, 3, 2, 1]]
I want to do this with loops/recursion. If I use recursion, I would probably have as basic step that the inner most elements get swapped first, and then from here on we would make the matrix bigger by also including the outer elements and swapping them too. However, I'm having trouble with the recursion step. After having swapped the inner most elements, I want to include the next to inner most elements in the matrix, and swap them too, and then continue like this until we reach the outer elements. How can this be implemented in code? This is what I did so far:
matrix = [[1, 2, 3, 4],
[1, 2, 3, 4]]
def mirror(matrix):
# This corresponds to the basic step. The two inner most elements get swapped.
if len(matrix) == 2:
for i in range(len(matrix)):
for j in range(len(matrix)):
# Store one element in a temporal variable
temp = matrix[i][j]
matrix[i][j] = matrix[i][len(matrix) - 1]
matrix[i][len(matrix)-1] = temp
return matrix
else:
# Recursion step
for i in range(len(matrix)):
for j in range(len(matrix)):
return (matrix + mirror(matrix[(len(matrix) // 2) - 1 : len(matrix)]))
The recursion step is wrong I think. I tried using the slice operator, but I'm not sure how this should be done correctly. Any help with this problem would be appreciated.
A recursive solution is pretty trivial, just recurse across the array reversing each subarray:
arr= [[2, 1],
[4, 3]]
def reve(l):
# if we have recursed across all sub arrays just return empty list
if not l:
return []
# else reverse the first current sublist l[0] and recurse on the remaining sublists
return [l[0][::-1]] + reve(l[1:])
print(reve(arr))
[[1, 2], [3, 4]]
Which can be written concisely as:
def reve(l):
return [l[0][::-1]] + reve(l[1:]) if l else []
If you wanted it inplace:
arr = [[1, 2, 3, 4],
[1, 2, 3, 4]]
def reve(l):
if not l:
return
# call inplace list.reverse on each sublist
l[0].reverse()
return reve(l[1:])
reve(arr)
Output:
[[4, 3, 2, 1], [4, 3, 2, 1]]
And lastly we can achieve what you want inplace with no slicing at all using iter with the special method __length__hint:
def reve(l):
if l.__length_hint__() == 0:
return
sub = next(l)
sub.reverse()
return reve(l)
reve(iter(arr))
print(arr)
Output:
[[4, 3, 2, 1], [4, 3, 2, 1]]
Both functions might use the map function, but you can use a imperative for also. About my recursive approach, the else statement refers to all cases between the ultimate and second elements of the list, they are being concatenated until the first element is reached.
My recursive approach:
a = [[1, 2, 3],
[5, 6, 7]]
def mirror(matrix):
def revert(row):
if len(row) == 1:
return [row[0]]
else:
return [row[-1]] + revert(row[:-1]) # concatenates two lists.
return [revert(row) for row in matrix]
mirror(a)
My declarative approach:
def mirror(matrix):
def revert(row):
return row[::-1] # copies the array in reverse order
return list(map(revert, matrix)) #<-for python3, and just map(...) for python2
mirror(a)
Both functions outputs
[[3, 2, 1], [7, 6, 5]]
Actually, a more Pythonic way of doing that would be using list comprehensions. You can do that simply by:
matrix = [[1, 2, 3, 4],
[1, 2, 3, 4]]
reversed_matrix = (i[::-1] for i in matrix)
reversed_matrix will be a generator expression. You may convert it into a list by replacing "()" with "[]" In the list comprehension.
i[::-1] reverses the array in-place using slice operator
def is_list(p):
return isinstance(p, list)
def deep_reverse(p):
initial = []
for v, e in enumerate(p):
if is_list(e):
#print p[v][::-1]
initial.append(p[v][::-1])
deep_reverse(e)
return initial
p = [1, [2, 3, [4, [5, 6, [7, 8]]]]]
print deep_reverse(p)
I get [[[4, [5, 6, [7, 8]]], 3, 2]], expected at least (I haven't bothered to figure out how to not lose the very first list [1[...]] yet) [[[[6, 5, [8, 7]], 4], 3, 2]].
As you can see the code only reverses [ [2, 3]] --> [[3, 2]].
What did I do wrong? Haven't I though about?
This is how I would do it:
def deep_reverse(p):
return [deep_reverse(x) if isinstance(x, list) else x for x in p[::-1]]
p = [1, [2, 3, [4, [5, 6, [7, 8]]]]]
print deep_reverse(p) # [[[[[8, 7], 6, 5], 4], 3, 2], 1]
A more generic, Pythonic answer to this, based on Pavel Anossov's is as follows:
def deep_reversed(seq):
return [deep_reversed(x) if (isinstance(x, collections.Sequence) and
not isinstance(x, str)) else x
for x in reversed(seq)]
Note that this is for Python 3.x, in Python 2.x, you will want isinstance(x, basestring) instead to allow for Unicode strings.
This answer is a good one, as it will work correctly with any object that acts as a sequence - be it a list, a tuple, or a custom class. This means it's much more flexible.
Edit: If you wanted it to reverse strings internally:
def deep_reversed(seq):
for x in reversed(seq):
if isinstance(x, collections.Sequence):
if isinstance(x, str):
yield "".join(reversed(x))
else:
yield deep_reversed(x)
else:
yield x
Again, in 2.x, use isinstance(x, basestring).
There are already many nice solutions, but maybe this is the algorithm you are trying:
def is_list(p):
return isinstance(p, list)
def deep_reverse(p):
initial = p[::-1] # reverse this level
for v, e in enumerate(initial):
if is_list(e): # for all the sublist in this level
initial[v] = deep_reverse(e) # recursively call deep_reverse to reverse the sublist
return initial
p = [1, [2, 3, [4, [5, 6, [7, 8]]]]]
print deep_reverse(p)
In the recursive calls to deep_reverse(e) you are not using the returned value. It looks as though you are expecting it to modify the input list
You can change it to something like this:
def deep_reverse(p):
initial = []
for e in p[::-1]:
if is_list(e):
initial.append(deep_reverse(e)])
else:
initial.append(e)
return initial
This will solve your purpose:
import collections
def dr(p):
r=[]
for i in p:
if isinstance(i,collections.Iterable):
r.append(dr(i))
else:
r.append(i)
return r[::-1]