Given a list of integers, how can I group together consecutive numbers that share the same parity?
Here is an example input:
[5, 9, 11, 20, 24, 30, 31, 33, 39, 41]
And here is an example output:
[[5, 9, 11], [20, 24, 30], [31, 33, 39, 41]]
a simple loop does the job:
test = [5,7,9,11,13,20,22,24,31,33,39,41,43,44,46,50,52]
result = []
res = []
prevalue = None
for v in test:
if prevalue == None or v == prevalue + 2:
prevalue = v
res.append(v)
else:
prevalue = v
result+= [res]
res = [v]
result+= [res]
print(result)
result:
[[5, 7, 9, 11, 13], [20, 22, 24], [31, 33], [39, 41, 43], [44, 46], [50, 52]]
You can use itertools.groupby() to produce the groupings of odd / even numbers:
[list(group) for _, group in groupby(data, lambda x: x % 2 == 0)]
This outputs:
[[5, 9, 11], [20, 24, 30], [31, 33, 39, 41]]
Basically, what you want to do is track the current list you're looking at and modify it as you go and, when your condition no longer holds true, you save the list and create a new one:
results = []
current = [data[0]]
flag = data[0] % 2
for number in data[1:]:
if number % 2 == flag:
current.append(number)
else:
flag = 1 - flag
results.append(current)
current = [number]
results.append(current)
Related
Suppose I have a list like this, where numbers increase in different steps:
[ 0, 4, 6, 8, 12, 15, 19, 21, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]
I want to return the index for the first element in the list where the increase is incremental (+1 step only). In this case, 23 is the first location from which point the increase becomes incremental, and its index would be 8, which is what I want as an output.
What would be an elegant simple way to achieve this? This is what I have tried:
>>> for (a,b) in zip(l, l[1:]):
... if b-a == 1:
... print(l.index(a))
... break
UPDATE: In this particular setup, once the increase becomes incremental it will continue to stay that way. It is possible that the increase will never become incremental.
Solution 1: operator
from operator import sub, indexOf
L = [ 0, 4, 6, 8, 12, 15, 19, 21, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]
print(indexOf(map(sub, L[1:], L), 1))
# prints 8
Raises ValueError: sequence.index(x): x not in sequence if difference 1 never occurs, so might want to use try/except for that.
Solution 2: bisect
This one only takes O(log n) time, using the monotonicity of incrementalness (as you commented "once the increase becomes incremental it will continue to stay that way").
from bisect import bisect
L = [ 0, 4, 6, 8, 12, 15, 19, 21, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]
class IsIncremental:
def __getitem__(_, i):
return L[i+1] - L[i] == 1
print(bisect(IsIncremental(), False, 0, len(L) - 1))
# prints 8
Prints len(L) - 1 if difference 1 never occurs.
Btw... readability
As PEP 8 says:
Never use the characters 'l' (lowercase letter el), [...] as single character variable names. In some fonts, these characters are indistinguishable from the numerals one and zero. When tempted to use 'l', use 'L' instead.
Steps:
Iterate over the array until the second last element.
Check if next element value differs from current element value by exactly 1.
Print the index and break the loop.
Code:
my_list = [0, 4, 6, 8, 12, 15, 19, 21, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]
for i in range(len(my_list)-1):
if my_list[i+1] - my_list[i] == 1:
print(i)
break
Result:
8
Here is an iterative approach. We can loop over the list and take the following action at each index:
If the current value is one plus the previous, then don't move the incremental index
Otherwise, reset the incremental index to the current position
If we reach the end of the list and we have an incremental index which is earlier than the last position, then we have a potential match.
lst = [0, 4, 6, 8, 12, 15, 19, 21, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]
idx = 0
for i in range(1, len(lst)):
if lst[i] != lst[i-1] + 1:
idx = i
if idx < len(lst) - 1:
print("Found index: " + str(idx) + ", value: " + str(lst[idx]))
else:
print("No incremental index found")
This prints:
Found index: 8, value: 23
Do a for each loop and check the previous value with the current. Once you reach a point where your current value is only 1 greater than the previous value, return the index of the previous value in your array:
myList = [ 0, 4, 6, 8, 12, 15, 19, 21, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]
lastVal = -1000
for i in myList:
if i - lastVal == 1:
print(myList.index(lastVal)) #will print your desired value's index. If this is in a function, replace print with return
break
lastVal = i
if myList.index(lastVal) == len(myList) - 1:
print("There is no incremental increase in your array")
(edited, replaced return with lastVal, fixed to print the index)
Output:
8
Here is a way to do this using list comprehension
lst = [ 0, 4, 6, 8, 12, 15, 19, 21, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]
list2 = [i-1 for i,j in enumerate(lst) if j-lst[i-1]==1]
if len(list2)>0:
print(list2[0])
else:
print('No one up number exists')
Similar to the previous answer.
myList = [0, 4, 6, 8, 12, 15, 19, 21, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]
l0 = 0 #suppose that the initial value is 0
for l1 in myList:
increment = l1 - l0
if increment == 1:
print(myList.index(l0)) #if you want to get the second element, use l1 instead.
break #if you want to get all the first elements that has 1 increment, remove break
l0 = l1 #memorize l1
Takes a list of numbers and groups the numbers by their tens place, giving every tens place it's own sublist.
ex:
$ group_by_10s([1, 10, 15, 20])
[[1], [10, 15], [20]]
$ group_by_10s([8, 12, 3, 17, 19, 24, 35, 50])
[[3, 8], [12, 17, 19], [24], [35], [], [50]]
my approach:
limiting = 10
ex_limiting = 0
result = []
for num in lst:
row = []
for num in lst:
if num >= ex_limiting and num <= limiting:
row.append(num)
lst.remove(num)
result.append(row)
ex_limiting = limiting
limiting += 10
But it returns [[1], [10, 20]].
What's wrong with my approach and how can I fix it?
You may already have a correct answer, but here's an alternative solution:
def group_by_10s(mylist):
result = []
decade = -1
for i in sorted(mylist):
while i // 10 != decade:
result.append([])
decade += 1
result[-1].append(i)
return result
group_by_10s([8, 12, 3, 17, 19, 24, 35, 50])
#[[3, 8], [12, 17, 19], [24], [35], [], [50]]
It uses only plain Python, no extra modules.
You can use a list comprehension:
def group_by_10s(_d):
d = sorted(_d)
return [[c for c in d if c//10 == i] for i in range(min(_d)//10, (max(_d)//10)+1)]
print(group_by_10s([1, 10, 15, 20]))
print(group_by_10s([8, 12, 3, 17, 19, 24, 35, 50]))
print(group_by_10s(list(range(20))))
Output:
[[1], [10, 15], [20]]
[[3, 8], [12, 17, 19], [24], [35], [], [50]]
[[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [10, 11, 12, 13, 14, 15, 16, 17, 18, 19]]
Credit to advice for not iterating list during loop.
I got this answer at the end, for anyone who wants the answer.
Thanks for support!
def group_by_10s(numbers):
external_loop = int(max(numbers)/10)
limiting = 10
ex_limiting = 0
result = []
for external_loop_count in range(external_loop+1):
row = []
for num in numbers:
if num >= ex_limiting and num < limiting:
row.append(num)
row.sort()
result.append(row)
ex_limiting = limiting
limiting += 10
return(result)
How about this one?
numbers = [8, 12, 3, 17, 19, 24, 35, 50]
def group_by_10s(numbers):
arr = []
for i in range((max(numbers) / 10) + 1):
arr.append([])
numbers.sort()
for number in numbers:
if number < 10:
arr[0].append(number)
else:
index = number / 10
arr[index].append(number)
return arr
print group_by_10s(numbers)
# [[3, 8], [12, 17, 19], [24], [35], [], [50]]
Do not modify the list while you are iterating over it, as when you remove items from it, some items get skipped over. Also change the bounds so that you will only append to row if num < limiting. I would add in a check to make sure the list has elements before adding it to result:
for num in lst:
row = []
for num in lst:
if num >= ex_limiting and num < limiting:
row.append(num)
if len(row) > 0 :
result.append(row)
ex_limiting = limiting
limiting += 10
This will yield:
[[1], [10, 15], [20]]
I've created a list (which is sorted):
indexlist = [0, 7, 8, 12, 19, 25, 26, 27, 29, 30, 31, 33]
I want to extract the numbers from this list that are at least five away from each other and input them into another list. This is kind of confusing. This is an example of how I want the output:
outlist = [0, 7, 19, 25, 31]
As you can see, none of the numbers are within 5 of each other.
I've tried this method:
for index2 in range(0, len(indexlist) - 1):
if indexlist[index2 + 1] > indexlist[index2] + 5:
outlist.append(indexlist[index2])
However, this gives me this output:
outlist = [0, 12, 19]
Sure, the numbers are at least 5 away, however, I'm missing some needed values.
Any ideas about how I can accomplish this task?
You need to keep track of the last item you added to the list, not just compare to the following value:
In [1]: indexlist = [0, 7, 8, 12, 19, 25, 26, 27, 29, 30, 31, 33]
In [2]: last = -1000 # starting value hopefully low enough :)
In [3]: resultlist = []
In [4]: for item in indexlist:
...: if item > last+5:
...: resultlist.append(item)
...: last = item
...:
In [5]: resultlist
Out[5]: [0, 7, 19, 25, 31]
This should do the trick. Here, as I said in comment, the outlist is initialised with the first value of indexlistand iterated indexlist elements are compared to it. It is a rough solution. But works.
indexlist = [0, 7, 8, 12, 19, 25, 26, 27, 29, 30, 31, 33]
outlist = [indexlist[0]]
for index2 in range(1, len(indexlist) - 1):
if indexlist[index2] > (outlist[-1] + 5):
outlist.append(indexlist[index2])
output:
>>outlist
[0, 7, 19, 25, 31]
Tim Pietzcker's answer is right but this can also be done without storing the last added item in a separate variable. Instead you can read the last value in outlist:
>>> indexlist = [0, 7, 8, 12, 19, 25, 26, 27, 29, 30, 31, 33]
>>> outlist = []
>>> for n in indexlist:
... if not outlist or n > outlist[-1] + 5:
... outlist.append(n)
...
>>> outlist
[0, 7, 19, 25, 31]
I suppose your index_list is sorted. Then this will give you only indexes MIN_INDEX_OFFSET apart.
MIN_INDEX_OFFSET = 5;
index_list = [0, 7, 8, 12, 19, 25, 26, 27, 29, 30, 31, 33];
last_accepted = index_list[0];
out_list = [last_accepted];
for index in index_list:
if index-last_accepted > MIN_INDEX_OFFSET:
out_list.append(index);
last_accepted = index;
print(out_list)
I want to know how to print numbers which are in sorted list. The interval will be given. For example:
list = [5, 10, 14, 18, 20, 30, 55]
and our interval input is between 11 and 29. So the program must print 14, 18,20.
You can simmply do as follows:
a_list = [5, 10, 14, 18, 20, 30, 55]
print([v for v in a_list if 11 <= v <= 29])
# Prints [14, 18, 20]
number_list = [5, 10, 14, 18, 20, 30, 55]
interval_list = [11,29]
result_list = []
for number in number_list:
if number in range(interval_list[0], interval_list[1]):
result_list.append(number)
print result_list
This question already has answers here:
Modifying list while iterating [duplicate]
(7 answers)
Closed 8 years ago.
I have a function that takes two parameters (a list and an input number). I have code that breaks the input list into a smaller grouping of lists. I then need to check this new list and make sure all of the smaller lists are at least as long as the input number. However when I try to iterate over the sublists within my main list, for some reason certain sublists are excluded (in my example it is the sublist located at mainlist[1]. Any idea why this is happening???
def some_function(list, input_number)
...
### Here I have other code that further breaks down a given list into groupings of sublists
### After all of this code is finished, it gives me my main_list
...
print main_list
> [[12, 13], [14, 15, 16, 17, 18, 19], [25, 26, 27, 28, 29, 30, 31], [39, 40, 41, 42, 43, 44, 45]]
print "Main List 0: %s" % main_list[0]
> [12, 13]
print "Main List 1: %s" % main_list[1]
> [14, 15, 16, 17, 18, 19]
print "Main List 2: %s" % main_list[2]
> [25, 26, 27, 28, 29, 30, 31]
print "Main List 3: %s" % main_list[3]
> [39, 40, 41, 42, 43, 44, 45]
for sublist in main_list:
print "sublist: %s, Length sublist: %s, input number: %s" % (sublist, len(sublist), input_number)
print "index of sublist: %s" % main_list.index(sublist)
print "The length of the sublist is less than the input number: %s" % (len(sublist) < input_number)
if len(sublist) < input_number:
main_list.remove(sublist)
print "Final List >>>>"
print main_list
> sublist: [12, 13], Length sublist: 2, input number: 7
> index of sublist: 0
> The length of the sublist is less than the input number: True
> sublist: [25, 26, 27, 28, 29, 30, 31], Length sublist: 7, input number: 7
> index of sublist: 1
> The length of the sublist is less than the input number: False
> sublist: [39, 40, 41, 42, 43, 44, 45], Length sublist: 7, input number: 7
> index of sublist: 2
> The length of the sublist is less than the input number: False
> Final List >>>>
> [[14, 15, 16, 17, 18, 19], [25, 26, 27, 28, 29, 30, 31], [39, 40, 41, 42, 43, 44, 45]]
Why is my sublist located at mainlist[1] being completely skipped??? Thanks for any help in advance.
An 'if' in a list comprehension would work:
>>> x = [[12, 13], [14, 15, 16, 17, 18, 19], [25, 26, 27, 28, 29, 30, 31], [39, 40, 41, 42, 43, 44, 45]]
>>> [y for y in x if len(y)>=7]
[[25, 26, 27, 28, 29, 30, 31], [39, 40, 41, 42, 43, 44, 45]]
It looks like you're changing the list as you iterate over it. This is not allowed and can lead to undefined behavior.
See this answer.