Related
I have two lists (X and Y). I want to first scale the first element of X with all the elements of Y before moving to the second element of X which is then again scaled by all the elements of Y. How can I do this? Ideally, I would also like to append it to different lists (L) when a new element of X is started, but I am not sure if that is possible.
Y = [2, 3, 4, 5]
X = [1, 2, 3, 4]
L = []
for i in range(len(X)):
for j in range(len(Y)):
X_scale = X[i] * Y[j]
L.append(X_scale)
Preferred outcome:
# First element in X
X_scale = [2, 2, 3, 4]
X_scale = [3, 2, 3, 4]
X_scale = [4, 2, 3, 4]
X_scale = [5, 2, 3, 4]
# Second element in X
X_scale = [1, 4, 3, 4]
X_scale = [1, 6, 3, 4]
#etc
This seems to follow your pattern:
Y = [2, 3, 4, 5]
X = [1, 2, 3, 4]
L = []
for i,x in enumerate(X):
for y in Y:
X_scale = X.copy()
X_scale[i] = x * y
L.append(X_scale)
for row in L:
print(row)
Output:
[2, 2, 3, 4]
[3, 2, 3, 4]
[4, 2, 3, 4]
[5, 2, 3, 4]
[1, 4, 3, 4]
[1, 6, 3, 4]
[1, 8, 3, 4]
[1, 10, 3, 4]
[1, 2, 6, 4]
[1, 2, 9, 4]
[1, 2, 12, 4]
[1, 2, 15, 4]
[1, 2, 3, 8]
[1, 2, 3, 12]
[1, 2, 3, 16]
[1, 2, 3, 20]
Per OP's comment to group the indices:
Y = [2, 3, 4, 5]
X = [1, 2, 3, 4]
L = []
for i,x in enumerate(X):
L2 = []
for y in Y:
X_scale = X.copy()
X_scale[i] = x * y
L2.append(X_scale)
L.append(L2)
for row in L:
print(row)
Output:
[[2, 2, 3, 4], [3, 2, 3, 4], [4, 2, 3, 4], [5, 2, 3, 4]]
[[1, 4, 3, 4], [1, 6, 3, 4], [1, 8, 3, 4], [1, 10, 3, 4]]
[[1, 2, 6, 4], [1, 2, 9, 4], [1, 2, 12, 4], [1, 2, 15, 4]]
[[1, 2, 3, 8], [1, 2, 3, 12], [1, 2, 3, 16], [1, 2, 3, 20]]
First you can simply you loops by accessing the items directly, without an index. Then you can transform the inner loop into a comprehension list to make it more compact:
Y = [2, 3, 4, 5]
X = [1, 2, 3, 4]
L = []
for x_item in X:
L += [x_item * y_item for y_item in Y]
I have a list of values like this,
lst = [1, 2, 3, 4, 5, 6, 7, 8]
Desired Output:
window size = 3
1 # first element in the list
forward = [2, 3, 4]
backward = []
2 # second element in the list
forward = [3, 4, 5]
backward = [1]
3 # third element in the list
forward = [4, 5, 6]
backward = [1, 2]
4 # fourth element in the list
forward = [5, 6, 7]
backward = [1, 2, 3]
5 # fifth element in the list
forward = [6, 7, 8]
backward = [2, 3, 4]
6 # sixth element in the list
forward = [7, 8]
backward = [3, 4, 5]
7 # seventh element in the list
forward = [8]
backward = [4, 5, 6]
8 # eight element in the list
forward = []
backward = [5, 6, 7]
Lets assume a window size of 4, now my desired output:
for each_element in the list, I want 4 values in-front and 4 values backward ignoring the current value.
I was able to use this to get sliding window of values but this also not giving me the correct required output.
import more_itertools
list(more_itertools.windowed([1, 2, 3, 4, 5, 6, 7, 8], n=3))
Code:
arr = [1, 2, 3, 4, 5, 6, 7, 8]
window = 3
for backward, current in enumerate(range(len(arr)), start = 0-window):
if backward < 0:
backward = 0
print(arr[current+1:current+1+window], arr[backward:current])
Output:
[2, 3, 4], []
[3, 4, 5], [1]
[4, 5, 6], [1, 2]
[5, 6, 7], [1, 2, 3]
[6, 7, 8], [2, 3, 4]
[7, 8], [3, 4, 5]
[8], [4, 5, 6]
[], [5, 6, 7]
One Liner:
print(dict([(e, (lst[i+1:i+4], lst[max(i-3,0):i])) for i,e in enumerate(last)]))
Output:
{1: ([2, 3, 4], []),
2: ([3, 4, 5], [1]),
3: ([4, 5, 6], [1, 2]),
4: ([5, 6, 7], [1, 2, 3]),
5: ([6, 7, 8], [2, 3, 4]),
6: ([7, 8], [3, 4, 5]),
7: ([8], [4, 5, 6]),
8: ([], [5, 6, 7])}
Credit: thanks to suggestions from #FeRD and #Androbin, the solution now looks better
This should get you started:
from dataclasses import dataclass
from typing import List
#dataclass
class Window:
index: int
backward: List[int]
forward: List[int]
def window(iterable, window_size, index):
backward = iterable[max(0, index - window_size):index]
forward = iterable[index + 1:index + 1 + window_size]
return Window(index, backward, forward)
>>> window([1,2,3,4,5,6], 3, 0)
Window(index=0, backward=[], forward=[2, 3, 4])
>>> window([1,2,3,4,5,6], 3, 5)
Window(index=5, backward=[3, 4, 5], forward=[])
I would also suggest adding some checks whether the index and window size make sense.
If you are stuck with an older Python version that doesn't have dataclasses yet, you can use Named Tuples instead.
This will work with more_itertools.windowed if you adjust the window size. Since you want 7 items (3 backward, 1 current, 3 forward), set the window size to 7.
from itertools import chain
from more_itertools import windowed
n = 3
iterable = [1, 2, 3, 4, 5, 6, 7, 8]
# pad the iterable so you start with an empty backward window
it = chain([None] * n, iterable, [None] * n)
for window in windowed(it, n * 2 + 1):
print(window[n])
print('forward =', [x for x in window[n + 1:] if x is not None])
print('backward =', [x for x in window[:n] if x is not None])
The output is:
1
forward = [2, 3, 4]
backward = []
2
forward = [3, 4, 5]
backward = [1]
3
forward = [4, 5, 6]
backward = [1, 2]
4
forward = [5, 6, 7]
backward = [1, 2, 3]
5
forward = [6, 7, 8]
backward = [2, 3, 4]
6
forward = [7, 8]
backward = [3, 4, 5]
7
forward = [8]
backward = [4, 5, 6]
8
forward = []
backward = [5, 6, 7]
Your sliding window reminds me of another data structure: fixed-size stacks. If you think about it, what you want is actually a fixed-size stack of 7 elements where the right three are the forward window elements and the back three are the back window elements. The 4th element is the current element. Here's how I would do it:
import collections
my_list = [1, 2, 3, 4, 5, 6, 7, 8]
window = collections.deque([], 7)
for i in my_list:
window.append(i)
# Get the back three elements
forward_window = list(window)[-3:]
# Get the front three elements
backward_window = list(window)[:len(window)-4]
print()
print(list(forward_window))
print(list(backward_window))
Of course, the code is not exactly what you want as the stack needs to be primed with some starting elements but that can be done with a bit more work:
import collections
my_list = [1, 2, 3, 4, 5, 6, 7, 8]
# Start with the first three elements
window = collections.deque(my_list[:3], 7)
# Iterate from the fourth element
for i in my_list[3:]:
window.append(i)
forward_window = list(window)[-3:]
backward_window = list(window)[:len(window)-4]
print()
print(list(forward_window))
print(list(backward_window))
After that you just need to clear the stack by adding some empty elements:
while len(window) != 4:
window.popleft()
forward_window = list(window)[4:]
backward_window = list(window)[:3]
print()
print(list(forward_window))
print(list(backward_window))
Here is the quick code I wrote
lst = [1, 2, 3, 4, 5, 6, 7, 8]
sliding_window_size = 3
def get_sliding_list(l, index):
l_list = []
r_list = []
min_range = 0
if index > sliding_window_size:
min_range = index - sliding_window_size
max_range = len(l)
if index + sliding_window_size < len(l):
max_range = index + sliding_window_size + 1
return (l[min_range:index], l[index + 1:max_range])
print(get_sliding_list(lst, 0))
print(get_sliding_list(lst, 1))
print(get_sliding_list(lst, 2))
print(get_sliding_list(lst, 3))
print(get_sliding_list(lst, 4))
print(get_sliding_list(lst, 5))
print(get_sliding_list(lst, 6))
print(get_sliding_list(lst, 7))
Output
([], [2, 3, 4])
([1], [3, 4, 5])
([1, 2], [4, 5, 6])
([1, 2, 3], [5, 6, 7])
([2, 3, 4], [6, 7, 8])
([3, 4, 5], [7, 8])
([4, 5, 6], [8])
([5, 6, 7], [])
Pass index of the element for which you want to retrieve sliding window
You can just use min and max to make sure you stay within the list (no loops needed) .
lst = [1, 2, 3, 4, 5, 6, 7, 8]
ws = 3 # window
st = 3 # starting point
mn = max(st-ws-1, 0)
mx = min(st+ws, len(lst))
print('Forward = ',lst[st:mx])
print('Backward = ', lst[mn:st-1])
Output:
Forward = [4, 5, 6]
Backward = [1, 2]
Here's a short and neat code based on list comprehension.
forward = [lst[i+1:i+1+window] for i in range(len(lst)]
backward = [lst[::-1][i+1:i+1+window] for i in range(len(lst)] # first reverse the input list and do same as did in forward
out = zip(forward,backward[::-1]) # first reverse the backward list and zip two list into one
Output
>>> forward
[[2, 3, 4], [3, 4, 5], [4, 5, 6], [5, 6, 7], [6, 7, 8], [7, 8], [8], []]
>>> backward
[[7, 6, 5], [6, 5, 4], [5, 4, 3], [4, 3, 2], [3, 2, 1], [2, 1], [1], []]
>>> out
[([2, 3, 4], []), ([3, 4, 5], [1]), ([4, 5, 6], [2, 1]), ([5, 6, 7], [3, 2, 1]), ([6, 7, 8], [4, 3, 2]), ([7, 8], [5, 4, 3]), ([8], [6, 5, 4]), ([], [7, 6, 5])]
[ll[i-4:i+4] for i in range(4, len(ll)-4)]
does the trick, I should think.
I want to display a list with order modulo N, for exemple:
With N =6, I have a list l[k]=[1, 2, 3, 4, 5, 6], so I can display its revers l[-k]=[6,5,4,3,2,1] by the instruction l[::-1].
But now I want to display l[(-k)mod N] which is [1,6,5,4,3,2] and then l[(1-k)mod N] which is [2,1,6,5,4,3] and so on.
Is there any instruction in python for display a list like that?
>>> l = [1,2,3,4,5,6]
>>> N = len(l)
>>> revL = l[::-1]
>>> revL
[6, 5, 4, 3, 2, 1]
>>> for i in range(1,N):
... print revL[-i:] + revL[:(N-i)]
...
[1, 6, 5, 4, 3, 2]
[2, 1, 6, 5, 4, 3]
[3, 2, 1, 6, 5, 4]
[4, 3, 2, 1, 6, 5]
[5, 4, 3, 2, 1, 6]
Similiar questions to this one have been asked before, but none exactly like it an and I'm kind of lost.
If I have 2 sets of lists (or a lists of lists)
listOLists = [[1,2,3],[1,3,2]]
listOLists2 = [[4,5,6],[4,6,5]]
And I want 'merge' the two lists to make
mergedLists = [[1,2,3,4,5,6],[1,3,2,4,5,6],[1,2,3,4,6,5],[1,3,2,4,6,5]]
How would I do this?
list1s=[[1,2,3],[3,2,1],[2,2,2]]
list2s=[[3,3,3],[4,4,4],[5,5,5]]
for indis1 in list1s:
for indis2 in list2s:
print(indis1 + indis2)
try and;
[1, 2, 3, 3, 3, 3]
[1, 2, 3, 4, 4, 4]
[1, 2, 3, 5, 5, 5]
[3, 2, 1, 3, 3, 3]
[3, 2, 1, 4, 4, 4]
[3, 2, 1, 5, 5, 5]
[2, 2, 2, 3, 3, 3]
[2, 2, 2, 4, 4, 4]
[2, 2, 2, 5, 5, 5]
You may use generator to simplify your code, like this:
a = [[1, 2, 3], [1, 3, 2], [2, 1, 3]]
b = [[4, 5, 6], [4, 6, 5], [5, 4, 6]]
c = [i + j for i in a for j in b]
print c
Output:
[[1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 6, 5], [1, 2, 3, 5, 4, 6], [1, 3, 2, 4, 5, 6], [1, 3, 2, 4, 6, 5], [1, 3, 2, 5, 4, 6], [2, 1, 3, 4, 5, 6], [2, 1, 3, 4, 6, 5], [2, 1, 3, 5, 4, 6]]
list1 = [[1,2,3],[1,3,2]]
list2 = [[4,5,6],[4,6,5]]
mergedLists = []
for list1_inner in list1:
for list2_inner in list2:
mergedLists.append(list1_inner + list2_inner)
print(mergedLists)
A comparison of methods:
import itertools
import random
l1 = [[random.randint(1,100) for _ in range(100)]for _ in range(100)]
l2 = [[random.randint(1,100) for _ in range(100)]for _ in range(100)]
With itertools:
def itert(l1, l2):
[list(itertools.chain(*x)) for x in itertools.product(l1, l2)]
With for loops:
def forloops(list1, list2):
mergedLists = []
for list1_inner in list1:
for list2_inner in list2:
mergedLists.append(list1_inner + list2_inner)
With a simple Comprehension:
def comp(l1, l2):
[i + j for i in l1 for j in l2]
Speed
%time itert(l1, l2)
Wall time: 99.8 ms
%time comp(l1, l2)
Wall time: 31.3 ms
%time forloops(l1, l2)
Wall time: 46.9 ms
x = []
for i in l[0::3]:
x.append(i)
for j in l[1::3]:
x.append(j)
for k in l[2::3]:
x.append(k)
print(x)
I want to take a random list like
[1, 2, 3, 4, 5, 6, 7]
that would return
[1, 4, 7, 2, 5, 4, 7]
but for a list of any number. is there a way to increase the start by 1 ?
Using list comprehension:
>>> xs = [1, 2, 3, 4, 5, 6, 7]
>>> [x for i in range(3) for x in xs[i::3]]
[1, 4, 7, 2, 5, 3, 6]