Better way to get sublist in python - python

I am working on the following problem:
This function returns a list of all possible sublists in L of length n without skipping elements in L. The sublists in the returned list should be ordered in the way they appear in L, with those sublists starting from a smaller index being at the front of the list.
Example 1, if L = [10, 4, 6, 8, 3, 4, 5, 7, 7, 2] and n = 4 then your function should return the list [[10, 4, 6, 8], [4, 6, 8, 3], [6, 8, 3, 4], [8, 3, 4, 5], [3, 4, 5, 7], [4, 5, 7, 7], [5, 7, 7, 2]]
My solution works but how can I make it shorter? What is a better way to do this?
def getSublists(L, n):
newN = n
myList = []
for i in range(len(L)):
orginalLen = L[i:n]
if(len(orginalLen) == n):
myList.append(L[i:n])
n = n + 1
else:
myList.append(L[i:n])
n = n + 1
if(newN == 1):
print(myList)
else:
print(myList[:len(myList)-(n-1)])
getSublists([10, 4, 6, 8, 3, 4, 5, 7, 7, 2],4)
getSublists([1], 1)
getSublists([0, 0, 0, 0, 0], 2)
OUTPUT
[[10, 4, 6, 8], [4, 6, 8, 3], [6, 8, 3, 4], [8, 3, 4, 5], [3, 4, 5, 7], [4, 5, 7, 7], [5, 7, 7, 2]]
[[1]]
[[0, 0], [0, 0], [0, 0], [0, 0]]

l = [1,2,3,4,5,6,87,9]
n = ..
print [l[i:i+n] for i in range(len(l)-n+1)]
maybe you need.

In one line:
get_sublists = lambda ls, n: [ls[x:x+n] for x in range(len(ls)-n+1)]
get_sublists([10, 4, 6, 8, 3, 4, 5, 7, 7, 2], 4)
[[10, 4, 6, 8], [4, 6, 8, 3], [6, 8, 3, 4], [8, 3, 4, 5], [3, 4, 5, 7], [4, 5, 7, 7], [5, 7, 7, 2]]

def get_sublists(L, n):
return [ L[i:i+n] for i in range(len(L)-n) ]

I completed the program a little better understanding of the reader.
def getSublists(L, n):
new_list = []
for i in range(len(L)-n+1):
a = L[i:i+n]
new_list.append(a)
return new_list
answer:
[[10, 4, 6, 8],
[4, 6, 8, 3],
[6, 8, 3, 4],
[8, 3, 4, 5],
[3, 4, 5, 7],
[4, 5, 7, 7],
[5, 7, 7, 2]]

This is pretty readable I think, to understand the concept. The idea here is to iterate through the numbers from 0 to the length of L, minus 4. And just take the sublist of L from your current index i, to i+4. Iterating to length-4 ensures you don't try to access an index out of bounds!
>>> for i in range(len(L)-4+1):
print L[i:i+4]
[10, 4, 6, 8]
[4, 6, 8, 3]
[6, 8, 3, 4]
[8, 3, 4, 5]
[3, 4, 5, 7]
[4, 5, 7, 7]
[5, 7, 7, 2]

Related

Split list into sublists of length x (with or without overlap)

There are many similar questions on here, but I can't find exactly what I'm looking for.
I want to split a list into sublists, each of which is exactly length x. This can include overlap, and the area of overlap doesn't matter so much. For example:
list_to_split = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
max_len = 3
desired_result = [[1, 2, 3], [3, 4, 5], [6, 7, 8], [8, 9, 10]]
# or
max_length = 4
desired_result = [[1, 2, 3, 4], [4, 5, 6, 7], [7, 8, 9, 10]]
# or
max_len = 5
desired_result = [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]]
It doesn't matter how many final sublists there are, though I don't want any more than necessary.
It also doesn't matter where the overlap happens, I just need to capture all the individual items in the original list and have each sublist result in the same number of items.
Thanks!
You can adjust the accepted answer by NedBatchelder in this thread to work for the described scenario.
This is a generator function which I think is a pretty neat solution.
def chunks(lst, n):
"""Yield successive n-sized chunks from lst."""
# n must not be 0
for i in range(0, len(lst), n):
if i + n >= len(lst):
yield lst[-n:]
else:
yield lst[i:i + n]
l = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
for i in range(1, 11):
print(list(chunks(l, i)))
Expected output:
[[1], [2], [3], [4], [5], [6], [7], [8], [9], [10]]
[[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]
[[1, 2, 3], [4, 5, 6], [7, 8, 9], [8, 9, 10]]
[[1, 2, 3, 4], [5, 6, 7, 8], [7, 8, 9, 10]]
[[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]]
[[1, 2, 3, 4, 5, 6], [5, 6, 7, 8, 9, 10]]
[[1, 2, 3, 4, 5, 6, 7], [4, 5, 6, 7, 8, 9, 10]]
[[1, 2, 3, 4, 5, 6, 7, 8], [3, 4, 5, 6, 7, 8, 9, 10]]
[[1, 2, 3, 4, 5, 6, 7, 8, 9], [2, 3, 4, 5, 6, 7, 8, 9, 10]]
[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]
The trick as I see it is to iterate an index in steps of x but "clip" the last one to be no less than x from the end:
>>> a = list(range(1, 11))
>>> x = 3
>>> [a[i:i+x] for i in (min(i, len(a) - x) for i in range(0, len(a), x))]
[[1, 2, 3], [4, 5, 6], [7, 8, 9], [8, 9, 10]]
Taken straight from itertools' recipes:
from itertools import zip_longest
def grouper(iterable, n, *, incomplete='fill', fillvalue=None):
"Collect data into non-overlapping fixed-length chunks or blocks"
# grouper('ABCDEFG', 3, fillvalue='x') --> ABC DEF Gxx
# grouper('ABCDEFG', 3, incomplete='strict') --> ABC DEF ValueError
# grouper('ABCDEFG', 3, incomplete='ignore') --> ABC DEF
args = [iter(iterable)] * n
if incomplete == 'fill':
return zip_longest(*args, fillvalue=fillvalue)
if incomplete == 'strict':
return zip(*args, strict=True)
if incomplete == 'ignore':
return zip(*args)
else:
raise ValueError('Expected fill, strict, or ignore')
You may then use the "fill" option, and add the last item continuously if you wish to guarantee the size of the sublist:
>>> list_to_split = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> max_len = 3
>>> list(grouper(list_to_split, max_len, fillvalue=list_to_split[-1]))
[(1, 2, 3), (4, 5, 6), (7, 8, 9), (10, 10, 10)]
Iterate over the list, slicing max_len elements at a time. We start the slice at min(idx, len(list_to_split) - max_len)) in case we're too close to the end of the list:
list_to_split = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
max_len = 3
result = []
for idx in range(0, len(list_to_split), max_len):
start = min(idx, len(list_to_split) - max_len)
result.append(list_to_split[start:start + max_len])
print(result)
You can turn this into a list comprehension, but it's admittedly not very readable:
list_to_split = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
max_len = 3
result = [
list_to_split[
min(idx, len(list_to_split) - max_len):
min(idx, len(list_to_split) - max_len) + max_len]
for idx in range(0, len(list_to_split), max_len)
]
print(result)
Both of these output:
[[1, 2, 3], [4, 5, 6], [7, 8, 9], [8, 9, 10]]
Following code should do without any libraries, though there are many libraries too that you can use
def main():
'''The Main'''
l = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
x = 3
print([l[i:i+x] for i in range(0, len(l), x)])
if __name__ == '__main__':
main()
Output
[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]

Select and compare every element in a column-list

I am trying to solve this puzzle question:
There is only one five-digit number n, such that every one of the following ten numbers share exactly one digit in common in the same position as n. Find n.
I'm trying to get like this:
https://i.stack.imgur.com/hufIc.jpg
For each column, selects every element and compares it along the column if it matches the same number. And then, appends it to get which number were matched on every column.
should i add if's in here:
L = [[0, 1, 2, 6, 5],
[1, 2, 1, 7, 1],
[2, 3, 2, 5, 7],
[3, 4, 5, 4, 8],
[4, 5, 9, 7, 0],
[5, 6, 2, 3, 6],
[6, 7, 3, 2, 4],
[7, 8, 0, 8, 4],
[8, 9, 8, 7, 2],
[9, 9, 4, 1, 4]]
for c in range(10):
for r in range(5):
print(L[c][r], end=' ')
print()
The easiest way I can think of is to get all the values of a column in a variable and then check if any value occurs more than once. The solution would look something like:
L = [
[0, 1, 2, 6, 5],
[1, 2, 1, 7, 1],
[2, 3, 2, 5, 7],
[3, 4, 5, 4, 8],
[4, 5, 9, 7, 0],
[5, 6, 2, 3, 6],
[6, 7, 3, 2, 4],
[7, 8, 0, 8, 4],
[8, 9, 8, 7, 2],
[9, 9, 4, 1, 4]
]
for r in range(5):
val = [L[c][r] for c in range(10)]
for i in range(10):
if val[i] in val[:i]:
print(val[i], end=" ")
break
else:
print(0, end=" ")
print()
L = [
[0, 1, 2, 6, 5],
[1, 2, 1, 7, 1],
[2, 3, 2, 5, 7],
[3, 4, 5, 4, 8],
[4, 5, 9, 7, 0],
[5, 6, 2, 3, 6],
[6, 7, 3, 2, 4],
[7, 8, 0, 8, 4],
[8, 9, 8, 7, 2],
[9, 9, 4, 1, 4]
]
for col_index in range(5):
col= [row[col_index] for row in L]
duplicate = [x for x in col if col.count(x) > 1]
if len(duplicate) == 0:
print(0, end=" ")
else:
print(duplicate[0], end=" ")
print()

padding while creating sublists

Is there an elegant way how to pad the last sublist with zeroes while creating sublists from a list of integers?
So far I have this oneliner and need to fill the last sublist with 2 zeroes
[lst[x:x+3] for x in range(0, len(lst), 3)]
for example
lst =[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
result should be:
[1,2,3][4,5,6][7,8,9][10,0,0]
With itertools.zip_longest, consuming the same iterator created off of the list, and fill in the missing values as 0 :
[[*i] for i in itertools.zip_longest(*[iter(lst)] * 3, fillvalue=0)]
Example:
In [1219]: lst =[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
In [1220]: [[*i] for i in itertools.zip_longest(*[iter(lst)] * 3, fillvalue=0)]
Out[1220]: [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 0, 0]]
Without itertools:
lst = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print([lst[x:x+3]+[0]*(x-len(lst)+3) for x in range(0, len(lst), 3)])
Prints:
[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 0, 0]]

Replacing items in a list in all possible permutations

Let's say I have a list or an array of the type:
mylist = [1, 2, 3, 4]
And I want to replace an item in this list. Normally I would use something like the following:
mylist[2] = 7
That works well. However, can someone explain how to create all possible permutations of mylist when replacing one or more items in mylist. For example, I want to create the following:
[7, 2, 3, 4]
[7, 7, 3, 4]
[7, 2, 7, 4]
[7, 7, 7, 4]
[7, 2, 3, 7]
...(and so on)
I know I can use itertools to generate all possible permutations, but how can I specify that I want to substitute an item in all possible locations in the list before generating the permutations? Here is how I tried to use itertools:
list(itertools.permutations([1,2,3,4,7], 4))
This doesn't work because it doesn't substitute 7 more than one time per permutation, and it also generates permutations that do not include the number 7.
Use itertools.combinations to find the indices to replace:
replace = 7
mylist = [1, 2, 3, 4]
for i in range(1, len(mylist) + 1):
for selected in itertools.combinations(range(len(mylist)), i):
res = mylist[:]
for n in selected:
res[n] = replace
print(res)
Output:
[7, 2, 3, 4]
[1, 7, 3, 4]
[1, 2, 7, 4]
[1, 2, 3, 7]
[7, 7, 3, 4]
[7, 2, 7, 4]
[7, 2, 3, 7]
[1, 7, 7, 4]
[1, 7, 3, 7]
[1, 2, 7, 7]
[7, 7, 7, 4]
[7, 7, 3, 7]
[7, 2, 7, 7]
[1, 7, 7, 7]
[7, 7, 7, 7]
You can create a function and just pass the list and value to that function and you get what you want :
import itertools
def replaced_it(list_1,value):
final_list = []
len_=len(list_1)
track_index = [k for k, j in enumerate(list_1)]
for i in range(len(track_index) + 1):
empty_list = [value]
replaced_one = list_1[:]
for ia in itertools.permutations(track_index, r=i):
if ia:
for i, j in zip(ia, empty_list * len(ia)):
replaced_one[i] = j
if replaced_one not in final_list:
final_list.append(replaced_one)
replaced_one = list_1[:]
return final_list
print(replaced_it([1,2,3,4],7))
output:
[[7, 2, 3, 4], [1, 7, 3, 4], [1, 2, 7, 4], [1, 2, 3, 7], [7, 7, 3, 4], [7, 2, 7, 4], [7, 2, 3, 7], [1, 7, 7, 4], [1, 7, 3, 7], [1, 2, 7, 7], [7, 7, 7, 4], [7, 7, 3, 7], [7, 2, 7, 7], [1, 7, 7, 7], [7, 7, 7, 7]]

filtering a list of entries in python

I need to filter a list of character ie
In [16]: list
Out[16]: [[1, 2, 3, 4, 5, 6, 7, 8], [2, 3, 6, 3, 6, 2, 7], [4, 5, 9, 3, 1, 8]]
characters to grep is, g = [4,8]
In [27]: a = filter(lambda x:g in x, list)
In [28]: a
Out[28]: []
But I am ending up with this. Can someone help me?
I need the output as
[[1, 2, 3, 4, 5, 6, 7, 8], [4, 5, 9, 3, 1, 8]]
Your issue is that g in x is never True because g is a list that and that is never within one of your sub-lists, e.g. ([4,8] in [4,8,7] returns False). The right approach with filter:
l = [[1, 2, 3, 4, 5, 6, 7, 8], [2, 3, 6, 3, 6, 2, 7], [4, 5, 9, 3, 1, 8]]
g = [4,8]
filter(lambda x:all(c in x for c in g), l)
# [[1, 2, 3, 4, 5, 6, 7, 8], [4, 5, 9, 3, 1, 8]]
Or list comprehension:
[item for item in l if all(c in item for c in g)]
# [[1, 2, 3, 4, 5, 6, 7, 8], [4, 5, 9, 3, 1, 8]]
Note, don't name your variables list, this shadows the built-in name

Categories

Resources