Python list range access as a ring buffer - python

I have a Python list and would like to build the ranged loop list. It looks like a ring buffer. So if I have a list:
[[0], [1], [2], [3]]
I would like to get:
[[0], [1], [2], [3]]
[[1], [2], [3], [4]]
[[2], [3], [4], [0]]
[[3], [4], [0], [1]]
[[4], [0], [1], [2]]
I could do it by myself. But is there any better or smarter ways in Python 3?
The code I have tried:
N = 5
d_list = [[_] for _ in range(N)]
for i in range(N):
b1 = i
e1 = i + N - 1
b2, e2 = 0, 0
if e1 >= N:
e2 = e1 - N
print(d_list[b1:e1] + d_list[b2:e2])

what about using a collections.deque and rotate ?
import collections
N = 5
d = collections.deque(range(N))
for _ in range(N):
print(d)
d.rotate(1)
result:
deque([0, 1, 2, 3, 4])
deque([4, 0, 1, 2, 3])
deque([3, 4, 0, 1, 2])
deque([2, 3, 4, 0, 1])
deque([1, 2, 3, 4, 0])
rotate just changes the start of the list, no data is copied/moved, so it's very fast.
note:
you can convert into list if needed
my example is using integers, not lists containing one sole integer. This can be easily adapted if necessary.

This Python function rotates anything slice-able as you desire:
def rotate(l, y=1):
if len(l) == 0:
return l
y = -y % len(l) # flip rotation direction
return l[y:] + l[:y]
>>> rotate([1,2,3,4,5],2)
[4, 5, 1, 2, 3]
>>> rotate([1,2,3,4,5],-22)
[3, 4, 5, 1, 2]
>>> rotate('abcdefg',3)
'efgabcd'
>>> for i in range(N):
... print(d_list)
... d_list=rotate(d_list)
...
[[0], [1], [2], [3], [4]]
[[4], [0], [1], [2], [3]]
[[3], [4], [0], [1], [2]]
[[2], [3], [4], [0], [1]]
[[1], [2], [3], [4], [0]]
Note that in Python 3, range is not sliceable. You first would need to create a list with list(range(...))
The sign convention is the same as deque.rotate

Related

Creating multiple sublists in Python

I have a list J with len(J)=2. I want to create a sublist of each element in J[i] where i=0,1. I present the current and expected output.
J = [[1, 2, 4, 6, 7],[1,4]]
arJ1=[]
for i in range(0,len(J)):
J1=[J[i]]
arJ1.append(J1)
J1=list(arJ1)
print("J1 =",J1)
The current output is
J1 = [[[1, 2, 4, 6, 7], [1, 4]]]
The expected output is
J1 = [[[1], [2], [4], [6], [7]], [[1], [4]]]
you can try this,
J = [[1, 2, 4, 6, 7],[1,4]]
new_l = []
for l in J:
tmp = []
for k in l:
tmp.append([k])
new_l.append(tmp)
print(new_l)
this will give you
[[[1], [2], [4], [6], [7]], [[1], [4]]]
With simple list comprehension:
res = [[[i] for i in sub_l] for sub_l in J]
print(res)
[[[1], [2], [4], [6], [7]], [[1], [4]]]
You can do in one line with list comprehension:
[[[k] for k in l] for l in J]
J = [[1, 2, 4, 6, 7],[1,4]]
arJ1 = []
for in_list in J:
new_list = []
for x in in_list:
new_list.append([x])
arJ1.append(new_list)
print(arJ1)

Making each element of a nested list a list

I have a nested list say:
lst = [[1,2,3,4], [2,3,4,5], [3,4,5,6]]
And I would like the output to be:
new_list = [[[1], [2], [3], [4]], [[2], [3], [4], [5]], [[3], [4], [5], [6]]]
this is what i am thinking, but I it is outputting a flat, list of list.
new_lst = []
for i in lst:
i = list(i)
for el in i:
new_list.append([el])
print(new_lst)
I would like to maintain the length of each predefined list in lst
Try List comprehension
[[ [e] for e in l] for l in lst]
You could use list comprehension and append every element to another list.
lst = [[1,2,3,4], [2,3,4,5], [3,4,5,6]]
new = [[[numbers] for numbers in elements] for elements in lst]
The above example adjusts for your desired output.
[[[1], [2], [3], [4]], [[2], [3], [4], [5]], [[3], [4], [5], [6]]]
You can use numpy's reshape np.reshape
>>> import numpy as np
>>> lst = np.array([[1,2,3,4], [2,3,4,5], [3,4,5,6]])
>>> lst
array([[1, 2, 3, 4],
[2, 3, 4, 5],
[3, 4, 5, 6]])
>>> lst.shape
(3, 4)
>>> lst.reshape(3,4,1)
array([[[1],
[2],
[3],
[4]],
[[2],
[3],
[4],
[5]],
[[3],
[4],
[5],
[6]]])
>>> lst.reshape(3,4,1).tolist()
[[[1], [2], [3], [4]], [[2], [3], [4], [5]], [[3], [4], [5], [6]]]
Another version, using recursion (you can have more level of depths in your input):
lst = [[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6]]
def split(i):
if isinstance(i, list):
return [split(v) for v in i]
else:
return [i]
print(split(lst))
Prints:
[[[1], [2], [3], [4]], [[2], [3], [4], [5]], [[3], [4], [5], [6]]]
You could use helper function to have more flexibility later of how you divide the smaller lists. based on an answer from here.
def split_list(alist, wanted_parts=1):
length = len(alist)
return [ alist[i*length // wanted_parts: (i+1)*length // wanted_parts]
for i in range(wanted_parts) ]
lst = [[1,2,3,4], [2,3,4,5], [3,4,5,6]]
ret =[]
for mini_list in lst:
ret.append(split_list(mini_list, len(mini_list)))
I think you had the right idea using multiple for loops. This should work:
list = [[1,2,3,4], [2,3,4,5], [3,4,5,6]]
for i in range(0, 3):
for j in range(0, 4):
(list[i])[j] = [(list[i])[j]]

Transposing the list

I have the following list:
y = [[0], [0], [0], [0], [1], [1], [1], [1]]
I would like to transpose it and have it in the following form:
[[0]
[0]
[0]
[0]
[1]
[1]
[1]
[1]]
When I did numpy.transpose(y), I got the following:
[[0 0 0 0 1 1 1 1]]
Any ideas?
[[0], [0], [0], [0], [1], [1], [1], [1]]
is exactly the same as this form:
[[0]
[0]
[0]
[0]
[1]
[1]
[1]
[1]]
You had a matrix with 8 rows and 1 column. Transposition executed on the matrix converted it to a matrix with just 1 row and 8 columns, so the output was correct.
If y is a list of lists, it displays as a single line
In [1]: y = [[0], [0], [0], [0], [1], [1], [1], [1]]
In [2]: y
Out[2]: [[0], [0], [0], [0], [1], [1], [1], [1]]
In [3]: print(y)
[[0], [0], [0], [0], [1], [1], [1], [1]]
You could of course do a line by line print
In [4]: for i in y: print(i)
[0]
[0]
[0]
[0]
[1]
[1]
[1]
[1]
If I make an array from it, I get a 2d (n,1) array
In [5]: Y = np.array(y)
In [6]: Y
Out[6]:
array([[0],
[0],
[0],
[0],
[1],
[1],
[1],
[1]])
In [7]: print(Y)
[[0]
[0]
[0]
[0]
[1]
[1]
[1]
[1]]
The array display does show rows and columns. Note that array print does not include commas (but its repr does).
If I transpose it, I get a (1,n) array, which displays as 1 line
In [8]: Y.T
Out[8]: array([[0, 0, 0, 0, 1, 1, 1, 1]])
There 3 different things that you may be confusing - the list, its print or string representation, and an array constructed from the list (and its print).
There is a list version of 'transpose':
In [9]: list(zip(*y))
Out[9]: [(0, 0, 0, 0, 1, 1, 1, 1)]
A longer list of lists may display as you want (if it doesn't neatly fit one line):
In [20]: z=[[i] for i in range(15)]
In [21]: z
Out[21]:
[[0],
[1],
[2],
[3],
[4],
[5],
[6],
[7],
[8],
[9],
[10],
[11],
[12],
[13],
[14]]
Except - that's an ipython pretty print action. In a plain python
shell
>>> [[i] for i in range(15)]
[[0], [1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11], [12], [13], [14]]
Which just emphasizes my point - there's a difference between a list and its print representation.
There is a pprint.pprint (pretty print) that behaves more like ipython, switching to row prints when the list gets too long.

List all contiguous sub-arrays

I have an array [1, 2, 3] of integer and I need to return all the possible combination of contiguous sub-arrays of this array.
[[1],[2],[3],[1,2],[2,3],[1,2,3]]
How can I handle that with python? One way would be to have 2 loops and the array itself but there should be a better way.
One line solution (I don't know what means "better way" for you)
L = [1,2,3]
[L[i:i+j] for i in range(0,len(L)) for j in range(1,len(L)-i+1)]
L=[1,2,3,4]
[L[i:i+j] for i in range(0,len(L)) for j in range(1,len(L)-i+1)]
you get,
[[1], [1, 2], [1, 2, 3], [2], [2, 3], [3]]
[[1],
[1, 2],
[1, 2, 3],
[1, 2, 3, 4],
[2],
[2, 3],
[2, 3, 4],
[3],
[3, 4],
[4]]
Simplifying the Inspector's solution:
def getAllWindows(L):
for w in range(1, len(L)+1):
for i in range(len(L)-w+1):
yield L[i:i+w]
And a solution using no loops at all:
def allSubArrays(L,L2=None):
if L2==None:
L2 = L[:-1]
if L==[]:
if L2==[]:
return []
return allSubArrays(L2,L2[:-1])
return [L]+allSubArrays(L[1:],L2)
def kwindow(L, k):
for i in range(len(L)-k+1):
yield L[i:i+k]
def getAllWindows(L):
for w in range(1, len(L)+1):
yield from kwindow(L, w)
Ouput:
In [39]: for i in getAllWindows([1,2,3]): print(i)
[1]
[2]
[3]
[1, 2]
[2, 3]
[1, 2, 3]
An itertools based approach:
import itertools
def allSubArrays(xs):
n = len(xs)
indices = list(range(n+1))
for i,j in itertools.combinations(indices,2):
yield xs[i:j]
For example:
>>> list(allSubArrays([1,2,3]))
[[1], [1, 2], [1, 2, 3], [2], [2, 3], [3]]
li=[1,2,3]
l=[]
for i in range(length(li)):
for j in range(i,len(li)+1):
if i==j: *cancelling empty sublist item*
continue
else:
subli=li[i:j]
l.append(subli)
print(l)
output:
[[1], [1, 2], [1, 2, 3], [2], [2, 3], [3]]

How to obtain sliced sublists of a list dynamically in python?

Let's say I have a list:
l = [0,1,2,3,4]
And I want to obtain a sequence of lists in this logic:
[[1,2,3,4],[0,1,2,3],[2,3,4],[1,2,3],[0,1,2],[3,4],[2,3],[1,2],[0,1],[0],[1],[2],[3],[4]]
That's it, sublists made of l[1:] and l[:-1]
I started by this recursive function:
l = [0,1,2,3,4]
def sublist(l):
if len(l) == 1:
return l
else:
return [sublist(l[1:]),sublist(l[:-1])]
a = [sublist(l)]
print a
But it's not really what I what as it outputs:
[[[[[[4], [3]], [[3], [2]]], [[[3], [2]], [[2], [1]]]], [[[[3], [2]], [[2], [1]]], [[[2], [1]], [[1], [0]]]]]]
import itertools
[list(itertools.combinations(l, x)) for x in range(1, len(l))]
Here's a very straightforward implementation:
def sublists_n(l, n):
subs = []
for i in range(len(l)-n+1):
subs.extend([l[i:i+n]])
return subs
def sublists(l):
subs = []
for i in range(len(l)-1,0,-1):
subs.extend(sublists_n(l,i))
return subs
>>> l = [0,1,2,3,4]
>>> sublists(l)
[[0, 1, 2, 3], [1, 2, 3, 4], [0, 1, 2], [1, 2, 3], [2, 3, 4], [0, 1], [1, 2], [2, 3], [3, 4], [0], [1], [2], [3], [4]]
[l[x:] for x in range(len(l))] + [l[:x+1] for x in range(len(l))]
Loops through l twice, but you sort of have to no matter what I think (could use zip but same thing).
A simple recursion, doesn't quite order things correctly but its simple.
def sublists(l):
right = l[1:]
left = l[:-1]
result = [right, left]
if len(l) > 2:
result.extend(sublists(right))
result.extend(sublists(left))
return result
print sublists([0,1,2,3,4])

Categories

Resources