def windows(iterable,n,m=1):
x = iter(iterable)
l = []
y = next(x)
for i in range(n):
l.append(y)
y = next(x)
yield l
while x:
for i in range(m):
l.pop(0)
for i in range(m):
l.append(y)
y = next(x)
yield l
I need to write a windows generator takes an iterable and two ints (call them n and m; with m’s default value 1) as parameters: it produces lists of n values: the first list contains the first n values; every subsequent list drops the first m from the previous list and adds the next m values from the iterable, until there are fewer than n values to put in the returned list.
for instance:
for i in windows('abcdefghijk', 4,2):
print(i,end='')
prints ['a','b','c','d'] ['c','d','e','f'] ['e','f','g','h'] ['g','h','i','j'].
when I call the above function, my code prints
[['i', 'j', 'k'], ['i', 'j', 'k'], ['i', 'j', 'k'], ['i', 'j', 'k']]
I cannot figure out the problem. can someone help me to fix it? Thanks in advance.
You should use slicing to grab n items and have a start value that increases by m.
def windows(iterable, n, m = 1):
if m == 0: # otherwise infinte loop
raise ValueError("Parameter 'm' can't be 0")
lst = list(iterable)
i = 0
while i + n < len(lst):
yield lst[i:i + n]
i += m
# Output
>>> for i in windows('abcdefghijk', 4, 2):
print(i)
['a', 'b', 'c', 'd']
['c', 'd', 'e', 'f']
['e', 'f', 'g', 'h']
['g', 'h', 'i', 'j']
Maybe something like this, assuming you aren't working with a lazy iterable.
def windows(iterable, n, m=1):
length = len(iterable)
i = 0
while i + n < length:
yield list(iterable[i:i + n])
i += m
for win in windows('abcdefghijk', 4, 2):
print(win)
output
['a', 'b', 'c', 'd']
['c', 'd', 'e', 'f']
['e', 'f', 'g', 'h']
['g', 'h', 'i', 'j']
appears to work for the few cases I tried, the generator itself is a one liner
def WindGen(astr, n, m = 1):
if m !=0:
return (list(astr[i * m : i * m + n]) for i in range((len(astr) - n) // m + 1))
astr = 'abcdefghijk'
n, m = 4, 2
print(*WindGen(astr, n, m), sep='\n')
['a', 'b', 'c', 'd']
['c', 'd', 'e', 'f']
['e', 'f', 'g', 'h']
['g', 'h', 'i', 'j']
The following will also work, and will not miss the end terms in some cases:
def sliding_window(iterable, window_size, step_size=1):
length = len(iterable)
i = 0
end_flag = False
while not end_flag:
curr_split = list(iterable[i:i + window_size])
if len(curr_split) < window_size:
end_flag = True
curr_split.extend([None] * (window_size - len(curr_split)))
yield curr_split
i += step_size
iterable = 'abcdefghijk'
window_size = 4
step_size = 2
res = list(sliding_window(iterable, window_size, step_size))
print(res)
Output:
[['a', 'b', 'c', 'd'],
['c', 'd', 'e', 'f'],
['e', 'f', 'g', 'h'],
['g', 'h', 'i', 'j'],
['i', 'j', 'k', None]]
Related
I have a version of this code working but it seems overly complex. This is the simplified version im getting stuck on. in python3.
list1 = [['a', 'b'], ['a', 'c'], ['a', 't'], ['x', 'f'], ['x', 'g'], ['d', 'z']]
z = len(list1)
for i in range(0, z):
for j in range(i + 1, z):
while list1[i][0] == list1[j][0]:
list1[i] = list1[i] + [list1[j][-1]]
if list1[j] in list1:
list1.remove(list1[j])
z = z - 1
I want output.
[['a', 'b', 'c', 't'], ['x', 'f', 'g'], ['d', 'z']]
Modding Darryl's a bit:
d = {}
for head, *tail in lst:
d.setdefault(head, [head]).extend(tail)
lst2 = list(d.values())
A simplfied construction is the following two steps.
d = {}
for sublist in lst:
d.setdefault(sublist[0], []).extend(sublist[1:])
lst2 = [[k] + v for k, v in d.items()]
print(lst2)
>>> [['a', 'b', 'c', 't'], ['x', 'f', 'g'], ['d', 'z']]
Explanation
(1) Dictionary d places items with the same first element as a dictionary key, with values corresponding to the remaining elements to produce:
{'a': ['b', 'c', 't'], 'x': ['f', 'g'], 'd': ['z']}
(2) Next, the list comprehension uses the key of each dictionary entry as the first element of a sublist and the value of the items as the remaining elements to produce the desired result
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
I have a list:
l = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']
Is there a way to create a list of lists so that:
l = [['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'i']]
And would it be possible to create the list of lists where the lists are of different sizes? For example:
l = [['a', 'b'], ['c', 'd', 'e', 'f'], ['g'], ['h', 'i']]
1 . For a multi-dimensioned list of defined inner list size :
>>> inner_size = 3
>>> out = [ l[i:i+inner_size] for i in range(0, len(l), inner_size) ]
>>> out
=> [['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'i']]
2 . For a multi-dimensioned list of random inner list size (this is kind of chunky unfortunately) :
>>> import random
>>> i=0
>>> out = []
>>> while i<len(l):
left_out = len(l) - i
inner_size = random.randint(1,left_out)
out.append(l[i: i+inner_size])
i += inner_size
>>> out
=> [['a'], ['b'], ['c', 'd', 'e', 'f', 'g'], ['h', 'i']]
For a consistent chunk size n, you can do:
l = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']
n = 3
l2 = [l[i:i + n] for i in range(0, len(l), n)]
l2
# [['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'i']]
Given split indexes (which you can easily generate from a list of chunk sizes), you can produce custom slices:
splits = [0, 2, 6, 7, 9]
l2 = [l[start:end] for start, end in zip(splits, splits[1:])]
l2
# [['a', 'b'], ['c', 'd', 'e', 'f'], ['g'], ['h', 'i']]
Here is a simple solution, you can set your own chunk sizes in the variable chunk_sizes either as a list or tuple or an integer
def chunk_list(l,chunk_sizes):
if isinstance(chunk_sizes,int):
for i in range(0,len(l),chunk_sizes):
yield l[i:i + chunk_sizes]
else:
start = 0
for size in chunk_sizes:
if start < len(l):
yield l[start:start + size]
start += size
l = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']
# custom chunk_sizes list
chunk_sizes = [2,4,1,2]
print ([sl for sl in chunk_list(l,chunk_sizes)])
#prints [['a', 'b'], ['c', 'd', 'e', 'f'], ['g'], ['h', 'i']]
# integer chunk_sizes
chunk_sizes = 3
print ([sl for sl in chunk_list(l,chunk_sizes)])
#prints [['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'i']]
One of the review questions for my midterm is to understand what this function does and I cannot read it because I don't understand where the parameters come from and how it works. Can somebody with programming experience help?
def enigma(numList, n, pos):
length = len(numList)
if pos == length:
print('Error')
return
newList = []
for i in range(pos):
newList = newList + [numList[i]]
newList = newList + [n]
tailLength = length - pos
counter = tailLength
while counter < length:
newList = newList + [numList[counter]]
counter = counter + 1
return newList
Many times trying some test data reveals the functionality quickly:
>>> enigma('abcdefghijklm', 'X', 0)
['X']
>>> enigma('abcdefghijklm', 'X', 1)
['a', 'X', 'm']
>>> enigma('abcdefghijklm', 'X', 2)
['a', 'b', 'X', 'l', 'm']
>>> enigma('abcdefghijklm', 'X', 3)
['a', 'b', 'c', 'X', 'k', 'l', 'm']
>>> enigma('abcdefghijklm', 'X', 4)
['a', 'b', 'c', 'd', 'X', 'j', 'k', 'l', 'm']
>>> enigma('abcdefghijklm', 'X', 12)
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'X', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm']
>>> enigma('abcdefghijklm', 'X', 13)
Error
The code starts with an empty new_list and builds it up in three sections
The repeating the first pos number of elements
Adding the n element
Repeating the trailing pos number of elements
As pos becomes larger than the midpoint, the beginning and trailing elements sections cross over to repeat some items.
In python, need to define a function that takes 2 lists. If the last part of the first list is same as first part of the second list, then delete the same part and added rest 2 lists together. such as:
I have defined a helper function called prefix that takes 2 lists and return true if the first list is prefix of the second list. Otherwise return false.
You could try:
def merge(seq1, seq2):
n1 = len(seq1)
for i in range(n1):
if seq1[i:] == seq2[:n1-i]:
return seq1 + seq2[n1-i:]
return seq1 + seq2
In [52]: merge(['a','a','a'],['g','g','g'])
Out[52]: ['a', 'a', 'a', 'g', 'g', 'g']
In [53]: merge(['a','t','t','a'],['t','t','a','a'])
Out[53]: ['a', 't', 't', 'a', 'a']
In [54]: merge(['a','t','t','a'],['t','t','a','a'])
Out[54]: ['a', 't', 't', 'a', 'a']
In [55]: merge(['a', 'a', 'a', 't', 't', 't', 't'], ['t', 't', 't', 't', 'g', 'g', 'g', 'g'])
Out[55]: ['a', 'a', 'a', 't', 't', 't', 't', 'g', 'g', 'g', 'g']
It doesn't modify the original lists, but you could do this easily if you need to.
(This isn't the way to go if your lists are very long with short overlaps because it checks from the beginning of the first.)
def merge(L1, L2):
middle = []
while L1 and L2 and L1[-1] == L2[0]:
middle.append(L2[0])
L1 = L1[:-2]
L2 = L2[1:]
return L1 + middle + L2
I've got a program that has a nested list which I wish to access and then append to a new list based on a condition. There are three columns in each list and I wish to know how to access them individually. Here's how it looks currently [['A', 'B', 'C'], ['D', 'E', 'F'], ['G', 'H', 'I']]. An example to better explain this would be, if I wanted data from the second column my new list would then look like ['B', 'E', 'H'].
This is what I have so far but I'm currently rather stuck..
n = 0
old_list = [['A', 'B', 'C'], ['D', 'E', 'F'], ['G', 'H', 'I']]
new_list = []
for a, sublist in enumerate(old_list):
for b, column in enumerate(sublist):
print (a, b, old_list[a][b])
if n == 0:
new_list.append(column[0])
if n == 1:
new_list.append(column[1])
if n == 2:
new_list.append(column[2])
print(new_list)
My current output..
0 0 A
0 1 B
0 2 C
1 0 D
1 1 E
1 2 F
2 0 G
2 1 H
2 2 I
['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I']
My desired output ..
n = 0
new_list = ['A', 'D', 'G']
n = 1
new_list = ['B', 'E', 'H']
n = 2
new_list = ['C', 'F', 'I']
Thanks for your help!
>>> L = [['A', 'B', 'C'], ['D', 'E', 'F'], ['G', 'H', 'I']]
>>> columns = list(zip(*L))
>>> columns
[('A', 'D', 'G'), ('B', 'E', 'H'), ('C', 'F', 'I')]
>>> columns[1] # 2nd column
('B', 'E', 'H')
Or if you want each column as a list to modify(since zip returns immutable tuples) then use:
columns = [list(col) for col in zip(*L)]
Another solution, which does not use the * construction nor zip():
for n in range(3):
print('n = {}'.format(n))
new_list = [sublist[n] for sublist in old_list]
print('new_list = {}'.format(new_list))