This question already has answers here:
How do I split a list into equally-sized chunks?
(66 answers)
Closed 6 years ago.
What is the simplest and reasonably efficient way to slice a list into a list of the sliced sub-list sections for arbitrary length sub lists?
For example, if our source list is:
input = [1, 2, 3, 4, 5, 6, 7, 8, 9, ... ]
And our sub list length is 3 then we seek:
output = [ [1, 2, 3], [4, 5, 6], [7, 8, 9], ... ]
Likewise if our sub list length is 4 then we seek:
output = [ [1, 2, 3, 4], [5, 6, 7, 8], ... ]
[input[i:i+n] for i in range(0, len(input), n)] # Use xrange in py2k
where n is the length of a chunk.
Since you don't define what might happen to the final element of the new list when the number of elements in input is not divisible by n, I assumed that it's of no importance: with this you'll get last element equal 2 if n equal 7, for example.
The documentation of the itertools module contains the following recipe:
import itertools
def grouper(n, iterable, fillvalue=None):
"grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"
args = [iter(iterable)] * n
return itertools.izip_longest(fillvalue=fillvalue, *args)
This function returns an iterator of tuples of the desired length:
>>> list(grouper(2, [1,2,3,4,5,6,7]))
[(1, 2), (3, 4), (5, 6), (7, None)]
A really pythonic variant (python 3):
list(zip(*(iter([1,2,3,4,5,6,7,8,9]),)*3))
A list iterator is created and turned into a tuple with 3x the same iterator, then unpacked to zip and casted to list again. One value is pulled from each iterator by zip, but as there is just a single iterator object, the internal counter is increased globally for all three.
I like SilentGhost's solution.
My solution uses functional programming in python:
group = lambda t, n: zip(*[t[i::n] for i in range(n)])
group([1, 2, 3, 4], 2)
gives:
[(1, 2), (3, 4)]
This assumes that the input list size is divisible by the group size. If not, unpaired elements will not be included.
Related
I do not want to use any other built-in functions so just want to experiment the available list methods.
I am trying to flatten the list with the code below:
my_list = [1, 2, 3, 6, 4, [0, 8, 9]]
new_list = []
for num in my_list:
new_list.extend([num])
print(new_list)
Expecting an output like this: [1, 2, 3, 6, 4, 0, 8, 9]
Getting the following output: [1, 2, 3, 6, 4, [0, 8, 9]]
The extend function is used to append all the elements of an iterable to the existing list. But the above code isn't working.
You have a mixed array so you need to check for that. So a function like
def flatlist(l):
if l== []:
return []
elif type(l) is not list:
return [l]
else:
return flatlist(l[0]) + flatlist(l[1:])
my_list = [1, 2, 3, 4, 5, 6, 7, 8, 9]
reversed_list = my_list.sort(reverse=True)
print(reversed_list)
When i type this code python returns the word "None" and i can not figure out why i can't assign a variable to act as a reversed list. An explanation or a solution for this problem will be greatly appreciated.
The method sort() does not return anything. Instead, it changes the list in place. So the correct code would be:
my_list = [1, 2, 3, 4, 5, 6, 7, 8, 9]
reversed_list = my_list.copy()
reversed_list.sort(reverse=True)
print(reversed_list)
If you don't need both lists, you can avoid copying and do the sorting on my_list instead, thus saving some memory.
U can use sorted() if u don't wanna change ur list object. sorted() function can sort any iterable & return a list of items in that iterable sorted manner.
Eg. sorted('abicd', reverse=True) will return ['i', 'd', 'c', 'b', 'a']
Sort changes ur list object in place & doesn't return anything i. e, None in python.
U can better code it like:
my_list = [1, 2, 3, 4, 5, 6, 7, 8, 9]
reversed_list = sorted(my_list, reverse=True)
print(reversed_list)
as follows I have a 2-D list/array
list1 = [[1,2],[3,4]]
list2 = [[3,4],[5,6]]
how can I use the function as union1d(x,y)to make list1 and list2 as one list
list3 = [[1,2],[3,4],[5,6]]
union1d just does:
unique(np.concatenate((ar1, ar2)))
so if you have a method of finding unique rows, you have the solution.
As described in the suggested link, and elsewhere, you can do this by converting the array to a 1d structured array. Here the simple version is
If arr is:
arr=np.array([[1,2],[3,4],[3,4],[5,6]])
the structured equivalent (a view, same data):
In [4]: arr.view('i,i')
Out[4]:
array([[(1, 2)],
[(3, 4)],
[(3, 4)],
[(5, 6)]],
dtype=[('f0', '<i4'), ('f1', '<i4')])
In [5]: np.unique(arr.view('i,i'))
Out[5]:
array([(1, 2), (3, 4), (5, 6)],
dtype=[('f0', '<i4'), ('f1', '<i4')])
and back to 2d int:
In [7]: np.unique(arr.view('i,i')).view('2int')
Out[7]:
array([[1, 2],
[3, 4],
[5, 6]])
This solution does require a certain familiarity with compound dtypes.
Using return_index saves that return view. We can index arr directly with that index:
In [54]: idx=np.unique(arr.view('i,i'),return_index=True)[1]
In [55]: arr[idx,:]
Out[55]:
array([[1, 2],
[3, 4],
[5, 6]])
For what it's worth, unique does a sort and then uses a mask approach to remove adjacent duplicates.
It's the sort that requires a 1d array, the rest works in 2d
Here arr is already sorted
In [42]: flag=np.concatenate([[True],(arr[1:,:]!=arr[:-1,:]).all(axis=1)])
In [43]: flag
Out[43]: array([ True, True, False, True], dtype=bool)
In [44]: arr[flag,:]
Out[44]:
array([[1, 2],
[3, 4],
[5, 6]])
https://stackoverflow.com/a/16971324/901925 shows this working with lexsort.
================
The mention of np.union1d set me and Divakar to focus on numpy methods. But it starting with lists (of lists), it is likely to be faster to use Python set methods.
For example, using list and set comprehensions:
In [99]: [list(x) for x in {tuple(x) for x in list1+list2}]
Out[99]: [[1, 2], [3, 4], [5, 6]]
You could also take the set for each list, and do a set union.
The tuple conversion is needed because a list isn't hashable.
One approach would be to stack those two input arrays vertically with np.vstack and then finding the unique rows in it. It would be memory intensive as we would discard rows from it thereafter.
Another approach would be to find the rows in the first array that are exclusive to it, i.e. not present in the second array and thus just stacking those exclusive rows alongwith the second array. Of course, this would assume that there are unique rows among each input array.
The crux of such a proposed memory-saving implementation would be to get those exclusive rows from first array. For the same we would convert each row into a linear index equivalent considering each row as an indexing tuple on a n-dimensional grid, with the n being the number of columns in the input arrays. Thus, assuming the input arrays as arr1 and arr2, we would have an implementation like so -
# Get dim of ndim-grid on which linear index equivalents are to be mapped
dims = np.maximum(arr1.max(0),arr2.max(0)) + 1
# Get linear index equivalents for arr1, arr2
idx1 = np.ravel_multi_index(arr1.T,dims)
idx2 = np.ravel_multi_index(arr2.T,dims)
# Finally get the exclusive rows and stack with arr2 for desired o/p
out = np.vstack((arr1[~np.in1d(idx1,idx2)],arr2))
Sample run -
In [93]: arr1
Out[93]:
array([[1, 2],
[3, 4],
[5, 3]])
In [94]: arr2
Out[94]:
array([[3, 4],
[5, 6]])
In [95]: out
Out[95]:
array([[1, 2],
[5, 3],
[3, 4],
[5, 6]])
For more info on setting up those linear index equivalents, please refer to this post.
I'd like to repeat elements of a list based on a predicate.
I tried using the module itertools and a list comprehension
abc = [1,2,3,4,5,6,7,8,9]
result = [ repeat(item,2) if item==3 or item==7 else item for item in abc ]
This doesn't fail at runtime, but the resulting object is not 'flattened'
If I print it, I see
[1, 2, repeat(3, 2), 4, 5, 6, repeat(7, 2), 8, 9]
Is it doable with a list comprehension?
Thanks
This works:
from itertools import repeat
abc = [1,2,3,4,5,6,7,8,9]
result = [x for y in (repeat(item,2) if item==3 or item==7 else [item] for item in abc)
for x in y]
>>> result
[1, 2, 3, 3, 4, 5, 6, 7, 7, 8, 9]
The trick here is to put item in its own list [item] and than flatten the now consistently nested list.
to improve readability, put it in two lines:
nested_items = (repeat(item,2) if item==3 or item==7 else [item] for item in abc)
result = [item for nested_item in nested_items for item in nested_item]
Since nested_items is an iterator, there is no extra list created her.
I have multiple lists to work with. What I'm trying to do is to take a certain index for every list(in this case index 1,2,and 3), in a vertical column. And add those vertical numbers to an empty list.
line1=[1,2,3,4,5,5,6]
line2=[3,5,7,8,9,6,4]
line3=[5,6,3,7,8,3,7]
vlist1=[]
vlist2=[]
vlist3=[]
expected output
Vlist1=[1,3,5]
Vlist2=[2,5,6]
Vlist3=[3,7,3]
Having variables with numbers in them is often a design mistake. Instead, you should probably have a nested data structure. If you do that with your line1, line2 and line3 lists, you'd get a nested list:
lines = [[1,2,3,4,5,5,6],
[3,5,7,8,9,6,4],
[5,6,3,7,8,3,7]]
You can then "transpose" this list of lists with zip:
vlist = list(zip(*lines)) # note the list call is not needed in Python 2
Now you can access the inner lists (which in are actually tuples this now) by indexing or slicing into the transposed list.
first_three_vlists = vlist[:3]
in python 3 zip returns a generator object, you need to treat it like one:
from itertools import islice
vlist1,vlist2,vlist3 = islice(zip(line1,line2,line3),3)
But really you should keep your data out of your variable names. Use a list-of-lists data structure, and if you need to transpose it just do:
list(zip(*nested_list))
Out[13]: [(1, 3, 5), (2, 5, 6), (3, 7, 3), (4, 8, 7), (5, 9, 8), (5, 6, 3), (6, 4, 7)]
Use pythons zip() function, index accordingly.
>>> line1=[1,2,3,4,5,5,6]
>>> line2=[3,5,7,8,9,6,4]
>>> line3=[5,6,3,7,8,3,7]
>>> zip(line1,line2,line3)
[(1, 3, 5), (2, 5, 6), (3, 7, 3), (4, 8, 7), (5, 9, 8), (5, 6, 3), (6, 4, 7)]
Put your input lists into a list. Then to create the ith vlist, do something like this:
vlist[i] = [];
for l in list_of_lists:
vlist[i].append(l[i])