Counting consecutive numbers in a list - python

I couldn't find a question that was similar enough to mine to where I could develop a satisfactory answer.
I'm pretty new to Python (3.4.3). I am trying to add elements to an output list using a for loop by comparing each element of an input list to the next element in it.
Here is my code so far:
random_list=[1,4,5,6,7,9,19,21,22,23,24]
def count_consec(random_list):
count=1
consec_list=[]
for i in listrand:
if listrand[i] == listrand[i+1]+1:
count+=1
else:
list.append(count)
return consec_list
Basically, I want to add to consec_list[] values that represent how the length of consecutive blocks of numbers in random_list[].
I expect my output in this case to look like this:
[1,4,1,1,4]
As in, there is one singular number, followed by 4 consecutive numbers, followed by one singular number, followed by one singular number, followed by 4 consecutive numbers.
I tried many different ways and I have gotten the function to build a list, but all the elements are 1s.

You could take an approach like this:
def countlist(random_list):
retlist = []
# Avoid IndexError for random_list[i+1]
for i in range(len(random_list) - 1):
# Check if the next number is consecutive
if random_list[i] + 1 == random_list[i+1]:
count += 1
else:
# If it is not append the count and restart counting
retlist.append(count)
count = 1
# Since we stopped the loop one early append the last count
retlist.append(count)
return retlist

There are a few problems with your code, among others undefined variables, or using an element i from the list as the index of that element, but also you will get an index error for the last element, and you never add the last count to the result list.
Instead, I'd suggest using the zip(lst, lst[1:]) recipe for iterating pairs of elements from the list, and using consec[-1] to access and modify the counts already in the list.
def count_consec(lst):
consec = [1]
for x, y in zip(lst, lst[1:]):
if x == y - 1:
consec[-1] += 1
else:
consec.append(1)
return consec
random_list=[1,4,5,6,7,9,19,21,22,23,24]
print(count_consec(random_list))
# [1, 4, 1, 1, 4]
Alternatively, you could subtract the index from each element. This way, successive consecutive elements will end up being the same element. Now, you can just use itertools.groupby to group and count those elements.
>>> random_list=[1,4,5,6,7,9,19,21,22,23,24]
>>> [e-i for i, e in enumerate(random_list)]
[1, 3, 3, 3, 3, 4, 13, 14, 14, 14, 14]
>>> [sum(1 for _ in g) for _, g in itertools.groupby(_)]
[1, 4, 1, 1, 4]

The following code fixes it up. You were iterating over the elements of the list itself instead of the counter you were referencing.
random_list=[1,4,5,6,7,9,19,21,22,23,24]
def count_consec(listrand):
count=1
consec_list=[]
for i in range(len(listrand[:-1])):
if listrand[i]+1 == listrand[i+1]:
count+=1
else:
consec_list.append(count)
count=1
# Account for the last iteration
consec_list.append(count)
return consec_list
print(count_consec(random_list))
Returns this:
[1, 4, 1, 1, 4]

Here's my version
Say you had a list of numbers, which you want to loop through and count the consecutive streaks:
list_of_nums = [4,5,7,8,2,1,3,5,7,6,8,9,9,9,2,2]
You could do something like this:
streak_count = []
counter = 1
for i in range(len(list_of_nums)):
if i != (len(list_of_nums) - 1):
diff = list_of_nums[i+1] - list_of_nums[i]
if diff == 1:
counter += 1
else:
streak_count.append(counter)
counter = 1
else:
streak_count.append(counter)

Related

how to loop through each element in list and increment by one

Hello i want to ask how to loop through each element and increment every time by one this is what i want first i want to sum 0 , 1, 3 ,6 , 10 and after that sum can somebody help me about that i don't know how to tell if it is loop through each element or iterate.It should look like these examples.I am sorry!
ls = [0, 1, 3, 6, 10]
ls = [1, 3, 6, 10]
ls = [3, 6, 10]
ls = [6, 10]
ls = [10]
ls = []
Here's the problem who i want to solve it :
https://www.codewars.com/kata/5ce399e0047a45001c853c2b/train/python
I tried this but it doesn't work
def parts_sums(ls):
length_list = len(ls)
for i in range(0,length_list+1):
return length_list
Note that there is a built-in function sum() in Python that does that job probably better than any code you can write in Python.
sum([0, 1, 3, 6, 10])
However, if you want to practice writing your sum function by iterating through a list and summing all the elements, this is how you do it.
def my_sum(ls):
result = 0
for i in range(len(ls)):
result += ls[i]
return result
First of all, you need to initialize a variable to hold your result. The range() function generates all values from 0 to x. The for-loop assigns all values generated by the range function to i in order and executes the indented block below. The += assignment increments the left-hand side variable by the right-hand side expression value. At last, we return the result.
And if you prefer using a while-loop,
def my_sum(ls):
result = 0
i = 0
while i < len(ls):
result += ls[i]
i += 1
return result
It's always good to consult Python documentation when you are not sure how to use its built-in function.
If you want the accumulated sum of all items reversed, you can take a look at the accumulate function in itertools.
from itertools import accumulate
def parts_sums(ls):
return list(accumulate(ls[::-1]))[::-1] + [0]
Or if you want to implement with a loop,
def parts_sums(ls):
result = []
part_sum = 0
for item in ls[::-1]:
result.append(part_sum)
part_sum += item
result.append(part_sum)
return result[::-1]
Or if you want to do it without reversing the list (say if you want to yield the results)
def parts_sums(ls):
result = []
part_sum = sum(ls)
for item in ls:
result.append(part_sum)
part_sum -= item
result.append(part_sum)
return result
Note the algorithm is still O(n), not that time complexity matters in this case.
For the question you have mentioned in codewars, you need to loop it thro 2 loops and keep reducing the first element in the inner loop for sum.
def parts_sums(ls):
# your code
sum = []
for i in range(len(ls)):
sum_temp =0
for j in range(i,len(ls)):
sum_temp += ls[j]
sum.append(sum_temp)
sum.append(0) # for the final empty list
return sum
print(parts_sums([0, 1, 3, 6, 10]))
This test will check the execution time too. So you need to be fast.
Naive approach
You can use sum or create your own sum.
def parts_sums(ls):
return [
sum(ls[i:])
for i in range(len(ls) + 1)
]
But i means you'll need to loop in a list twice. So it will be slow.
Sneaky approach
In a list like [a, b, c, d, e] you are calculating:
[a+b+c+d+e, a+b+c+d, a+b+c, a+b, a, 0]. So let's start from last to first element. [0, a, a+b, a+b+c, a+b+c+d, a+b+c+d+e]. Now we see a cumulative iteration:
So get loop in the list, get the element, sum it with last element of the result ([0]) list and add it as the last element to the result list. Lastly reverse the result.
def parts_sums(ls):
res = [0]
for i in range(len(ls)-1, -1, -1):
res.append(res[-1] + ls[i])
return res[::-1]

How to count numbers less than a given number including duplicates

I have a task to count numbers less than a given number. I understand this for most cases except ones with duplicates. So for example a list [1,2,2,3,4] I want the out put of this to be a count of 2 since it not including the middle one
One way I’ve tried this target is the number is the given number to find the less than to
count=0
for i in list:
if i< target:
count=count+1
return count
I know if I put = it will count both twos how can I fix this with what I have now and it still being a list
I would first remove duplicates like this:
res = []
[res.append(x) for x in list if x not in res]
and then you could get the number of values in the list without duplicates with the len function: len(res) or check each value to make sure it meets criteria before counting like being less then a number:
count = 0
for i in res:
if i < target: count += 1
return count
Although it might be faster to create a list of numbers that are both not duplicates and meet the criteria, and then just take the length of that list:
res = []
[res.append(x) for x in list if x not in res and x < target]
return len(res)
Put all the list items into a set and then count the number of elements less than target:
>>> a_list = [1, 2, 2, 3, 4]
>>> target = 3
>>> sum(i < target for i in set(a_list))
2
You can just change list to a set. That is, loop through a set of the list. This way you will go through each unique element once. See the code below:
count = 0
for element in set(list):
if element < target:
count += 1
print(count)
You can simply use a list comprehension:
target = 3 # can be any other number
len([x for x in set(myList) if x < target])

how to only sum a part of elements in a list

I need this function to return the sum of the elements located at the odd indices.
And that's what I have right now:
def getSumOdds(aList):
for element in aList:
if element % 2 == 1:
Since you are doing for element in aList, element % 2 == 1 will check if each element is odd, not if its index is odd.
What you can do is this:
value = 0
for index in range(len(aList)):
if index % 2 == 1:
value += aList[value]
This goes through all of the indices, and if it's odd, adds the element at that index to the accumulator.
That method is fairly easy to understand; however, it goes through an unnecessary number of elements:
value = 0
for index in range(1, len(aList), 2):
value += aList[index]
range(x, y, z) generates all elements counting up from x up to but not including y, counting by z. This starts at 1 and takes every 2 elements.
This is rather long though, and can be shortened to the following:
value = sum(aList[index] for index in range(1, len(aList), 2))
Using list slicing, where aList[start:end:jump] gives every jump-th element starting from start up to end (implicity the very end), you can do the following:
value = sum(aList[1::2])
This sums every second element starting from the first.
If your input is not necessarily indexable (that is, it's iterable but cannot use [index] syntax, such as a set, range, map, etc), you can do:
value = sum(val for index, val in enumerate(anIter) if index % 2 == 1)
This sums every value where the index is odd by getting the index and value for each enumerated value. The enumerate function is an iterable which returns (0, a[0]), (1, a[1]), ..., (len(a) - 1, a[-1]).
Using the code you've already started, enumerate is probably the function you want which returns the count and the values in the list. Then we filter the odd indices and add them to a variable for the sum, as you had already done:
def getSumOdds(aList):
total = 0
for index, element in enumerate(aList):
if index % 2 == 1:
total += element
return total
l = [1, 2, 3, 4, 5, 6, 7, 8, 9]
print getSumOdds(l) # 20 (odd indices: 2+4+6+8=20)
Just you can use a list slice list[1::2]
or function
def getSumOdds(aList):
return sum(aList[1::2])

Why is variable behaving differently outside loop?

if i run this code:
def numbers_in_lists(string):
next_number = 0
count = 0
final_list = []
while count < len(string):
number = int(string[count])
if number > next_number:
final_list.append(number)
new = []
next_number = number
else:
new.append(number)
if new not in final_list:
final_list.append(new)
count += 1
print final_list
#testcases
string = '543987'
result = [5,[4,3],9,[8,7]]
print repr(string), numbers_in_lists(string) == result
i get this answer:
'543987' [5, [4, 3], 9, [8, 7]]
False
but if i put the number variable outside of the while loop like this:
def numbers_in_lists(string):
next_number = 0
count = 0
final_list = []
number = int(string[count])
while count < len(string):
if number > next_number:
final_list.append(number)
new = []
next_number = number
else:
new.append(number)
if new not in final_list:
final_list.append(new)
count += 1
print final_list
i get this answer:
'543987' [5, [5, 5, 5, 5, 5]]
False
I am a beginner and i have looked everywhere for the explanation as to why the number variable behaves differently outside of the loop? Also, why are the other variables ok outside of the loop but not number variable?
Any help would be much appreciated. Thankyou. :)
You declare number as
number = int(string[count])
So when
count = 0
This means that number will be the first character of your string (position [0]) converted to int. If you do not update number within your loop, it will never change. In your first version of the code, number is in your while loop.
while count < len(string):
number = int(string[count])
# more code
count += 1
Note at the end of the loop, you increment count. This means at the beginning of the next iteration, count now is incremented, so number will take on the value of the next character in your string.
A common misconception for beginners is that a variable is somehow "bound" to another variable. For example:
>>> a = 5
>>> b = a
>>> b
5
>>> a = 7
>>> b
5
See, even though a changed values from 5 to 7, b doesn't change because it is not "bound" to that variable in any way. The line b = a means "take the value from a and assign it to b" after that, b doesn't care what happens to a.
The number = int(string[count]) uses the value of count assigned outside the loop which is the first character index 0, it will never change outside the loop, so you will always get the original value appended which is the first character.
Using number = int(string[count]) inside the loop you are reassigning number to the value of the element at index count each time so you get a different part of the input string appended each time.
Once you enter the while loop any values you change that were defined outside of the loop will not change outside that loop, you must reassign the value inside the loop.
I get that you are a beginner. Here is a rewrite that should help you with some useful python idioms and constructs:
def numbers_in_lists(string):
numbers = [int(c) for c in string]
next_number = -1
final_list = []
for number in numbers:
if number > next_number:
final_list.append(number)
final_list.append([])
next_number = number
else:
final_list[-1].append(number)
final_list = [x for x in final_list if x != []]
print final_list
First, be suspicious when you have a while-loop and a counter. You can replace it with a for-loop that iterates over all the items.
Since this code operates on integers, not characters in a string, let's translate them all at once using a list comprehension:
numbers = [int(c) for c in string]
This creates a list that has all the characters translated to integers.
By setting next_number = -1, we ensure that all numbers in numbers will be greater. In particular, the first element will be greater.
When we find a number that exceeds our last maximum, next_number, we add number and a bucket to put succeeding numbers less than number into:
if number > next_number:
final_list.append(number)
final_list.append([])
next_number = number
That means when we add 5, final_list looks like this:
[5, []]
And when number is 4 and 3, they get added properly:
[5, [4]]
[5, [4, 3]]
How does that happen? This code does it:
else:
final_list[-1].append(number)
Here we do not append to final_list; we append to the last list in final_list, final_list[-1].
But what if our sequence was just 5? Then at the end of the loop, final_list would look like this:
[5, []]
In that case, we want to trim out all empty lists, so we do it like this:
final_list = [x for x in final_list if x != []]
This says, "make final_list into a list that has all elements of final_list except those that are empty lists."
Good luck with learning python. I hope you find it rewarding.

recursive cumulative sums

I need to write a program that compute cumulative sums from a list of numbers with def but ONLY with recursion.
I did it, but now I need to write the same program without using the method sum, but no success so far.
Any idea?
my code:
def rec_cumsum(numbers):
''' Input: numbers - a list of numbers,
Output: a list of cumulative sums of the numbers'''
if len(numbers)==0: return numbers
return rec_cumsum(numbers[:-1])+ [sum(numbers)]
input:
1 [1,2,3]
2 [2, 2, 2, 3]
output:
1 [1,3,6]
2 [2, 4, 6, 9]
my code without sum:
def rec_cumsum(numbers):
''' Input: numbers - a list of numbers,
Output: a list of cumulative sums of the numbers'''
if len(numbers) == 0: return numbers
my_list=[]
rec_cumsum(my_list + numbers)
my_list[0]=numbers[0]
rec_cumsum(my_list)
temp_sum=my_list[0]+numbers[-1]
my_list[0]=temp_sum
return my_list
I would suggest something like this without adding additional arguments:
[UPDATED]
def rec(n):
if len(n) < 2: return n
n[1] = n[0] + n[1]
return [n[0]] + rec(n[1:])
print rec([1,2,3,4])
[1, 3, 6, 10]
What you can do is: -
Create a temp list(an empty one).
Pass your original list and the empty list in your method.
Now, when you pass your list for the first time, just add the first element from your original list to it. And call the same method with the rest of the list. Starting from 1st element.
When your method is invoked after wards, you need to take a sum of last element of your temp list and first element of the original list that is now modified. And add the sum to your temp list as new element.
Finally, when the length of your original list becomes 0. Return your temp.
**Here's the code for the above steps. You can compare it with the one you have implemented, and see where you went wrong: -
def rec_cumsum(numbers):
if len(numbers) == 0 : return temp
# You need to check, if `temp` is empty, that means method is called first time.
if not temp:
temp.extend([numbers[0]]) // Just add the first element to it.
else:
# Else, get the last element from `temp`,
# add it to `first elemt` in `numbers` and add it to `temp`.
temp.extend([temp[-1] + numbers[0]])
return rec_cumsum(numbers[1:])
my_list = [2, 2, 2, 3]
temp = []
print rec_cumsum(my_list)
yet another solution would be:
def rec(n):
if len(n) < 2: return n
rest = rec(n[:-1])
return rest + [rest[-1] + n[-1]]
this one feels more intuitive to me..

Categories