Using deque insert() to merge two lists? - python

I am attempting to insert a list of points into a deque, but I'm having trouble keeping it a continuous list:
from collections import deque
pts= deque()
pts = [1, 5]
new_pts = [2, 3, 4]
pts.insert(1,new_pts)
Output:
[1,[2, 3, 4], 5]
Desired output:
[1,2,3,4,5]
This works:
[pts.insert(1,pt) for pt in reversed(new_pts)]
But I'm afraid I'm overcomplicating things.

You can use simple slicing:
pts[1:1] = new_pts
Code:
pts = [1, 5]
new_pts = [2, 3, 4]
pts[1:1] = new_pts
print(pts)
# [1, 2, 3, 4, 5]

You need to use extendleft() to add more than one value to the beginning of the queue.
pts.extendleft(new_pts)

Related

Python - delete columns in 2D list

I have a 2D list = [[1, 8, 3], [4, 5, 6], [0, 5, 7]], and I want to delete columns in a loop.
For example, columns with index: 0(first) and 2(last) - - the result after deletions should be: [8, 5, 5].
There is a problem, because when I delete the 0th column, the size of the list is decreased to (0,1), and the 2nd index is out of scope.
What is the fastest method to delete columns in a loop without the out-of-scope problem?
For a better picture:
[[1, 8, 3],
[4, 5, 6],
[0, 5, 7]]
There is no such shortcut in python except for iterating over all the list items and removing those index values.
However, you can use pandas which is meant for some other purpose but will do the task.
import pandas as pd
s = [[1, 8, 3], [4, 5, 6], [0, 5, 7]]
df = pd.DataFrame(s,columns=['val1','val2','val3'])
li = df.drop('val1',axis=1).values.tolist()
now li will look like this
[[8, 3], [5, 6], [5, 7]]
You can use numpy like this:
import numpy as np
my_list = np.array([[1, 8, 3], [4, 5, 6], [0, 5, 7]])
new_list = my_list[:, 1].copy()
print(new_list)
Output:
>>> [8, 5, 5]
Also numpy.delete(your_list, index, axis) is do the same job:
new_list = np.delete(my_list,(0, 2), axis=1)
(0, 2) is the indices of the columns 0 and 2
axis=1 says numpy that (0, 2) are columns indices not rows.
if you want to delete rows 0 and 2 you can change axis=1 to axis=0
Output is a little different:
>>> array([[8],
[5],
[5]])
For a pure python approach:
my_list = [[1, 8, 3], [4, 5, 6], [0, 5, 7]]
new_list = [value[1] for value in my_list]
print(new_list)
Output:
>>> [8, 5, 5]
L is 2D list:
print(map(lambda x: x[1:], L))
data= [[1, 8, 3], [4, 5, 6], [0, 5, 7]]
index_to_remove=[0,2]
[list(x) for x in zip(*[d for i,d in enumerate(zip(*data)) if i not in index_to_remove])]
If I understood your question correctly, you want to keep the middle element (index 1) of each list,in that case I would suggest creating a new list. There could be other better ways, for sure. But you could try this, if this works for you:
twoD_list = [[1, 8, 3], [4, 5, 6], [0, 5, 7]]
def keep_col( twoD_list ,index_to_keep = 1):
final_list = []
for x in twoD_list:
final_list.append(x[index_to_keep])
return final_list
final_list = keep_col( twoD_list , 1)
Final output:
[8,5,5]
Assuming you always want only the second element and the inner lists always have at least two elements.
Pure python with list comprehension:
lst = [
[1, 8, 3],
[4, 5, 6],
[0, 5, 7],
]
filtered_lst = [
inner_element
for inner_lst in lst
for i, inner_element in enumerate(inner_lst)
if i == 1
]
print(filtered_lst)
# [8, 5, 5]
If you want you can the reassign the new list to the old variable:
lst = filtered_lst
The advantages of this method are:
no need to worry about the list being altered while you iterate it,
no need to import other libraries
list comprehension is built-in
list comprehension is often the fastest way to filter a list (see for example this article)
easier to read and maintain that other solutions (in my opinion).
Via itemgetter to extract the value at index 1.
from operator import itemgetter
my_list = [[1, 8, 3], [4, 5, 6], [0, 5, 7]]
result = list(map(itemgetter(1), my_list))
try this
my_list = [[1, 8, 3], [4, 5, 6], [0, 5, 7]]
filter_col=[0,2]
col_length=3
my_list=[[x[i] for i in range(col_length) if i not in filter_col] for x in my_list]
u do not want to directly mutate the list that you are working on
this performs a list comprehension to create a new list from the existing list
edit:
just saw u wanted only a flat list
assuming u only want one element for the list u can use
my_list=[x[1] for x in my_list]

Quicker way to join multiple lists passed as args to a Python function?

So I have a function which takes a variable number of lists as an argument, then combines those lists into one single list:
def comb_lists(*lists):
sublist = []
for l in lists:
sublist.extend(l)
print(sublist)
>>> comb_lists([1, 2], [3, 4], [5, 6])
[1, 2, 3, 4, 5, 6]
And it works. But I was just wondering if there was a simpler solution? I tried a list comprehension using list unpacking, but that returned a SyntaxError:
def comb_lists(*lists):
sublist = [*l for l in lists]
>>> comb_lists([1, 2], [3, 4], [5, 6])
SyntaxError: iterable unpacking cannot be used in comprehension
Is there any neater or quicker way to do this?
EDIT: itertools looks really useful for this sort of thing. I'd be interested to know if there's any way of doing it that doesn't rely on imports though.
here is the simplest solution
result = sum(lists, [])
There's built-in function chain.form_iterable() in itertools module to do this:
>>> from itertools import chain
>>> my_list = [[1, 2], [3, 4], [5, 6]]
>>> list(chain.from_iterable(my_list))
[1, 2, 3, 4, 5, 6]
If you do not want to import any module, you can write nested list comprehension to achieve this as:
>>> my_list = [[1, 2], [3, 4], [5, 6]]
>>> [e for l in my_list for e in l]
[1, 2, 3, 4, 5, 6]

Using zip_longest to sum different length lists and fill different lengths from start rather than end

I have two lists [1,2,3,4] and [1,2,3]
I would like to sum these to give me the following: [1,3,5,7].
This was done by doing 1+0=1, 2+1=3, 3+2=5 and 4+3=7.
I understand that itertools.zip_longest would do this, but it would fill the mismatch in length with 0 at the end, giving me [2,3,6,4] and not the value I want.
I would like the mismatch in length to be solved by filling the first length with zero.
The built-in reversed() function could be used to do it like this:
from itertools import zip_longest
def sum_lists(*iterables):
iterables = (reversed(it) for it in iterables)
return list(reversed([a+b for a, b in zip_longest(*iterables, fillvalue=0)]))
if __name__ == '__main__':
result = sum_lists([1, 2, 3, 4], [1, 2, 3])
print(result) # -> [1, 3, 5, 7]
result = sum_lists([1, 2, 3], [1, 2, 3, 4])
print(result) # -> [1, 3, 5, 7] # Order of args doesn't matter.
You can pad the second list with zeros and use zip:
s1, s2 = [1,2,3,4], [1, 2, 3]
new_result = [a+b for a, b in zip(s1, ([0]*(len(s1)-len(s2)))+s2)]
Output:
[1, 3, 5, 7]
You could build a shift by using repeat, then concatenate the shift with the shorter one using chain:
from itertools import repeat, chain
first = [1, 2, 3, 4]
second = [1, 2, 3]
shift = repeat(0, abs(len(first) - len(second)))
result = [a + b for a, b in zip(first, chain(shift, second))]
print(result)
Output
[1, 3, 5, 7]
You can use the reversed function to generate the two lists in reverse order so that zip_longest would align the zipping from the other end, and then reverse the result afterwards:
from itertools import zip_longest
lists = [1,2,3,4], [1, 2, 3]
print(list(map(sum, zip_longest(*map(reversed, lists), fillvalue=0)))[::-1])
This outputs:
[1, 3, 5, 7]
You could go around this problem be reversing your lists befor ziping with zip_longest.
from itertools import zip_longest
s1, s2 = [1,2,3,4], [1, 2, 3]
res = [a+b for a, b in zip_longest(reversed(s1), reversed(s2), fillvalue=0)]
and finally, reverse again, to produce the desired result:
res = res[::-1]
print(res) # [1, 3, 5, 7]
The main advantage of this method as #CoryKramer says in his comment is that you do not have to know beforehand which list is the longest.

How to do Math Functions on Lists within a List

I'm very new to python (using python3) and I'm trying to add numbers from one list to another list. The only problem is that the second list is a list of lists. For example:
[[1, 2, 3], [4, 5, 6]]
What I want is to, say, add 1 to each item in the first list and 2 to each item in the second, returning something like this:
[[2, 3, 4], [6, 7, 8]]
I tried this:
original_lst = [[1, 2, 3], [4, 5, 6]]
trasposition_lst = [1, 2]
new_lst = [x+y for x,y in zip(original_lst, transposition_ls)]
print(new_lst)
When I do this, I get an error
can only concatenate list (not "int") to list
This leads me to believe that I can't operate in this way on the lists as long as they are nested within another list. I want to do this operation without flattening the nested list. Is there a solution?
One approach using enumerate
Demo:
l = [[1, 2, 3], [4, 5, 6]]
print( [[j+i for j in v] for i,v in enumerate(l, 1)] )
Output:
[[2, 3, 4], [6, 7, 8]]
You can use enumerate:
l = [[1, 2, 3], [4, 5, 6]]
new_l = [[c+i for c in a] for i, a in enumerate(l, 1)]
Output:
[[2, 3, 4], [6, 7, 8]]
Why don't use numpy instead?
import numpy as np
mat = np.array([[1, 2, 3], [4, 5, 6]])
mul = np.array([1,2])
m = np.ones(mat.shape)
res = (m.T *mul).T + mat
You were very close with you original method. Just fell one step short.
Small addition
original_lst = [[1, 2, 3], [4, 5, 6]]
transposition_lst = [1, 2]
new_lst = [[xx + y for xx in x] for x, y in zip(original_lst, transposition_lst)]
print(new_lst)
Output
[[2, 3, 4], [6, 7, 8]]
Reasoning
If you print your original zip it is easy to see the issue. Your original zip yielded this:
In:
original_lst = [[1, 2, 3], [4, 5, 6]]
transposition_lst = [1, 2]
for x,y in zip(original_lst, transposition_lst):
print(x, y)
Output
[1, 2, 3] 1
[4, 5, 6] 2
Now it is easy to see that you are trying to add an integer to a list (hence the error). Which python doesn't understand. if they were both integers it would add them or if they were both lists it would combine them.
To fix this you need to do one extra step with your code to add the integer to each value in the list. Hence the addition of the extra list comprehension in the solution above.
A different approach than numpy that could work even for lists of different lengths is
lst = [[1, 2, 3], [4, 5, 6, 7]]
c = [1, 2]
res = [[l + c[i] for l in lst[i]] for i in range(len(c))]

Python list comprehension mirroring values

I tried to figure out the following problem through list comprehension but I couldn't make it work. I will show you how I solved the problem using a loop and a list comprehension.
So, I have a list that can have 0 to 6 elements in a range(6) and when I apply my function on it I want to change the values, as shown here:
l = [0, 1, 2, 3, 4, 5]
mirror = [5, 4, 3, 2, 1, 0]
I don't want to just rotate the array by 180 degrees but I actually want to replace the values. For example, my list looks like this now:
l = [2, 5]
Then l_inverted list should look like this:
l_inverted = [3, 0]
I came up with a regular way to solve it but ever since I started learning Python I've preferred list comprehensions.
l = [0, 3, 5]
mirror = [5, 4, 3, 2, 1, 0]
i = 0
for element in l:
l[i] = mirror[element]
i += 1
This actually inverts the l list. Here's my approach using a list comprehension:
l = [3, 5]
mirror = [5, 4, 3, 2, 1, 0]
for element in l:
print(element)
l = [mirror[element] if x==element else x for x in l]
This works fine.
Until:
l = [0, 3, 5]
mirror = [5, 4, 3, 2, 1, 0]
for element in l:
print(element)
l = [mirror[element] if x==element else x for x in l]
So it will replace 5 with 0, 2 with 3 and both 5s (the new one too) become 0. Obviously, I don't want it like that.
Should I stick to the working solution or is there a smooth way to solve it with list comprehensions? I'm trying to practice list comprehensions at all times but it's not fully in my brain yet. Thanks a lot.
If you want it as a list comprehension:
>> l = [0, 3, 5]
>> mirror = [5, 4, 3, 2, 1, 0]
>> l_inverted = [mirror[x] for x in l]
>> l_inverted
[5, 2, 0]
You are drowning in a spoonful of water and trying to take us with you.
You are using bad naming conventions that make your simple problem complicated to comprehend.
orig = [0, 1, 2, 3, 4, 5]
orig_rev = l[::-1]
selector = [0, 3, 5]
result = [orig_rev[i] for i in selector]
print(result ) # [5, 2, 0]
Based on your first two examples, it seems you are looking for the complement of each list value according to some base, similar to ones' complement. You could either hard-code the base as 5 or whatever, or you could assume it's the maximum number in the list and calculate it. Here's a solution for the latter:
Concept
<this complement> = <max value in list> - <this value>
Code
values = [0, 3, 2, 4, 5]
max_value = max(values)
complements = [max_value - value for value in values]
print complements
Result
[5, 2, 3, 1, 0]

Categories

Resources