How to slice a list that is sliced in python? - python

I have a list of let's say [[1,2,3,4], [1,2,3,4], [1,2,3,4], [1,2,3,4]] and its name is somelist. I want to do somelist[:2][:2] and have that return [[1,2], [1,2]]. So it slices the list and then slices that list and returns that. Is it even possible to do this in one line in python?

You can do this using list comprehension. I changed your sample input to make it clearer what is being selected:
>>> l = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]]
>>> print [x[:2] for x in l[:2]]
[[1, 2], [5, 6]]

Multidimensional slicing is easy with numpy:
import numpy
a = numpy.array([[1,2,3,4], [1,2,3,4], [1,2,3,4], [1,2,3,4]])
print(a[:2,:2])

Are your lists always 16 elements in a 4x4 matrix? If you are simply trying to get the 4 lower right corner elements, try:
>>> l = [[1,2,3,4], [1,2,3,4], [1,2,3,4], [1,2,3,4]]
>>> print [l[2][:2], l[3][:2]]
[[1, 2], [1, 2]]
Otherwise, for a general solution the list comprehension mentioned by others is better.
It would be interesting to benchmark both and see which is faster for your use case. Though this sounds like premature optimization to me.

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]

How can I split a list into a list of lists based on the difference between adjacent elements?

E.g., if I've got
MAX_ALLOWED_DIFF = 3
nums=[1, 2, 4, 10, 13, 2, 5, 5, 5]
the output should be
groups = [[1, 2, 4], [10, 13], [2, 5, 5, 5]]
The context: I had a pandas.Series object nums and I used
nums = nums.diff().gt(DETECTION_MAX_DIFF_NS).cumsum()).apply(list).tolist()
to subsample in the same fashion but I noticed that there're a lot of duplicates in my Series nums and after I use .unique() method I don't have Series object anymore, I've got numpy.ndarray (1D) instead.
I believe I may use sth like pandas.Series(nums.unique) but I don't like this hack.
So we using drop_duplicates, keep nums stay in pd.Series
nums=nums.drop_duplicates()
nums.groupby(nums.diff().abs().gt(MAX_ALLOWED_DIFF).cumsum()).apply(list).tolist()
Out[447]: [[1, 2, 4], [10, 13], [5]]
Here's one approach -
>>> import numpy as np
>>> idx = np.r_[0,np.flatnonzero(np.abs(np.diff(nums))>MAX_ALLOWED_DIFF)+1,len(nums)]
>>> [nums[i:j] for (i,j) in zip(idx[:-1],idx[1:])]
[[1, 2, 4], [10, 13], [2, 5, 5, 5]]
Given that you've tagged with numpy too, here's one way to do it:
thr = 3
ix = np.flatnonzero(np.concatenate([[False], np.abs(np.diff(nums))>thr]))
np.split(nums, ix)
Output
[array([1, 2, 4]), array([10, 13]), array([2, 5, 5, 5])]

Find sublists of innermost lists in 3d list

I have a list l=[[[1,2,3],[4,5,6]],[[7,8,9],[9,1,2]]]
How do I get the list [[[1,2],[4,5]],[[7,8],[9,1]]] using just slicing? I tried l[:][:][:2] but it gave me the entire 3d list.
You could use a nested list comprehension, of course this ins't only using slicing but hopefully still useful:
>>> lst = [[[1,2,3],[4,5,6]],[[7,8,9],[9,1,2]]]
>>> [[subsub[:-1] for subsub in sublist] for sublist in lst]
[[[1, 2], [4, 5]], [[7, 8], [9, 1]]]
Update: just noticed your outer lists do not need slicing. In that case:
Since you are on Python2 map works well on this one:
>>> from operator import itemgetter
>>> ft = itemgetter(slice(2))
>>>
>>> map(map, (ft, ft), l)
[[[1, 2], [4, 5]], [[7, 8], [9, 1]]]
The solution below was wrongly assuming the input list was 3 x 3 x 3 and to be sliced to 2 x 2 x 2. I'll leave it here in case anybody is looking for that case.
>>> from operator import itemgetter
>>> ft = itemgetter(slice(2))
>>>
>>> map(map, (ft, ft), map(ft, l[:2]))
[[[1, 2], [4, 5]], [[7, 8], [9, 1]]]

List comprehensions

I have a for loop for outputting values into a list.
This is my output:
[[23, 34, 34] [34,21,34,56] [21,3,5,67]]
Below is my code that works for the above output:
y_train = ([[word2index[w] for w in sent[1:]] for sent in tokenized_sentences]).
But I would like to append a value at the end of each smaller list. How can I modify my code to handle this? My desired output should look like this:
[[23,34,34,**2**][34,21,34,56,**2**][21,3,5,67,**2**]]
so I would like to append a new value at the end of each inner list.
P.S. A normal for loop handling this would be good too.
for x in y_train:
x.append(element)
example:
>>> listOfLists = [[1,2], [2,3], [4,5]]
>>> for x in listOfLists:
... x.append(2)
>>> listOfLists
[[1, 2, 2], [2, 3, 2], [4, 5, 2]]

Grouping Elements of Lists Within a List by Index

I am trying to take a list of lists, and return a list of lists which contain each element at an index of the original list of lists. I know that that's badly worded. Here's an example.
Say I have the following list of lists:
[[1,2,3], [4,5,6], [7,8,9]]
I want to get another list of lists, in which each list is a list of each elements at a specific index. For example:
[[1,2,3], [4,5,6], [7,8,9]] becomes [[1,4,7], [2,5,8], [3,6,9]]
So the first list in the returned list, contains all of the elements at the first index of each of the original list, and so on. I'm stuck, and have no idea how this could be done. Any help would be appreciated. Thanks.
>>> [list(t) for t in zip(*[[1,2,3], [4,5,6], [7,8,9]])]
[[1, 4, 7], [2, 5, 8], [3, 6, 9]]
perhaps an easy way wiould be:
a=[[1,2,3], [4,5,6], [7,8,9]]
b=zip(*a)
b will be equal to [(1, 4, 7), (2, 5, 8), (3, 6, 9)].
hopes this helps
Dan D's answer is correct and will work in Python 2.x and Python 3.x.
If you're doing lots of matrix operations, not just transposition, it's worth considering Numpy at this juncture:
>>> import numpy as np
>>> x = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
>>> np.swapaxes(x, 0, 1)
array([[1, 4, 7],
[2, 5, 8],
[3, 6, 9]])
Or, more simply, as per the comments, use numpy.transpose():
>>> np.transpose(x)
array([[1, 4, 7],
[2, 5, 8],
[3, 6, 9]])
In addition to the zip(*lists) approach, you could also use a list comprehension:
[[l[i] for l in lists] for i in range(3)]
In case you want to simply transpose your matrix -e.g. to get new matrix where rows are cols from initial matrix while columns equal to the initial matrix rows values then you can use:
initMatr = [
[1,2,3],
[4,5,6],
[7,8,9]
]
map(list, zip(*initMatr))
>>> [
[1,4,7],
[2,5,8],
[3,6,9]
]
OR in case you want to rotate matrix left then:
map(list, zip(*map(lambda x: x[::-1], initMatr)
>>> [
[3,6,9],
[2,5,8],
[1,4,7]
]

Categories

Resources