function that checks the length of the cycle - python

Hey guys i have the function, but it gives me error when I test it.
Does anyone have any Idea on how to fix it
This is my exercise. Please read through.
Write a function cycleLength(array), which returns the number of students that form a loop, given that you start by talking to the left-most one. The input array is a list of non-negative integers, such that array[m] is the number of the student to whom student m redirects. No student redirects to himself. The left-most student is number 0, the next is number 1, and so on. Each element in the list will be in the range [0, n-1] where n is the length of the list.
For example, suppose the list was [1, 3, 0, 1]. Then student 0 redirects to student 1, who redirects to student 3, who redirects back to student 1. There is a loop of two students: 1, 3. Thus the answer would be 2. Note that even though you started with student 0, he is not part of the loop.
Here is my function:
def cycleLength(m):
lst = []
i = 0
while i not in lst:
lst.append(i)
i = int(m[i])
b = len(lst) - lst.index(i)
return b

You almost got it right.
>>> def cycleLength(students):
... seen = []
... current = 0
... # Run till we have seen all the students
... while len(seen) != len(students):
... # If the current index has been seen already
... if current in seen:
... return len(seen) - seen.index(current)
... seen.append(current)
... current = students[current]
...
>>> assert(cycleLength([1, 3, 0, 1]) == 2)
>>> assert(cycleLength([1, 3, 0, 2]) is None)
This will take care of the case where there is no loop as well.

def cycleLength(m):
lst = []
for x in m:
if x in lst:
return len(lst) - lst.index(x)
lst.append(x)
return -1
Explanation:
you should loop while the element at index i m[i] is not already in lst - what you where doing is looking for the index in the list instead of "the element at index"
Same as previous point, you should append to lst the elements - not the index of the elements - otherwise you won't find any such "duplicate" elements - since the index should just increase.
Regards the last point - the index should keep increasing on each iteration
And last, the length of the cycle is between the first time that an element appears to the next time that you iterate the same element. And it's not necessarily from the beginning of the list.
Correction:
Previous version of the code had bugs, a simpler version of the same idea, and which is also bug-free (I believe), is posted here. -1 represents "no cycles found".

Related

get a code that Return True if in an array there is two 3 next to each-other?

#here is the code
def has_33(nums):
for i in range(0,len(nums)-1):
if nums[i:i+2]==[3,3]:
return True
return False
nums = [1,2,3,3]
print(has_33(nums))
questions:
why the code used len(nums)-1 in second line?(why used -1 ?)
in the 3rd line why do they used [i:i+2]==[3,3] and how does this code perform ?
please let me know ,
i am basically a noob in coding right now please help me to under stand how this code works
If you're looking for two elements in a row, there's no point in checking the last element of the list, since there's nothing after it. So the loop stops at the 2nd-to-last index.
nums[i:i+2] returns a slice of the list from element i to element i+1. Those are 2 consecutive elements. Then it compares this to [3, 3] to see if that pair of elements are two 3's next to each other.
Because a list of the length n has only n-1 pairs (for example, [1,2,3,4] has [1,2], [2,3] and [3,4])
Beacuse list[x:y] does not return element y of the list.
The following code is simple and should work for what you want to do.
a=[0, 1, 2, 0, 3]
def has_33():
last_i = 0
for i in a:
if last_i==3 and i==3:
return True
if i==3:
last_i = 3
return False
print(has_33())
Also works in different combinations of ...3,3...

Writing a Conditional For Loop to Sum a Subset of a List and Return Binary Value

I want to focus on a moving window of k in the lyst below, starting on the left and stopping one element short of the right edge. I want to take the sum of the 3 (k) items in the window. If the sum is >= k/2, append the value of 1 to the list "pred", otherwise append 0 to the list.
Here is my code so far:
lyst=[1,0,1,0,1]
k=3
pred=[]
for x in range(0, len(lyst)-k):
sumList=sum(lyst)
if sumList >= k/2:
pred.append(1)
else:
pred.append(0)
print(pred)
I know my sumList item is the issue here. I just need to adjust that so it generally sums k items to create 2 (that's len(lyst)-k) new values to pred. Each value will either be 0 or 1 depending on the condition.
Output should be:
pred=[1, 0]
Output I'm getting now:
pred=[1,1]
The critical part is taking only the required slice of lyst for your sum. Your start position is the left end for k elements of lyst:
for start in range(0, len(lyst)-k):
sumList = sum(lyst[start:start+k])
This will move a k-element window through lyst: [1, 0, 1], then [0, 1, 0]. These are greater than k/2 (yielding a 1) and less (for a 0).
Output:
[1, 0]
ADVANCED IMPLEMENTATION
You can build a list comprehension from the inside out, using the code in your (now repaired) loop.
lyst=[1,1,0,0,1]
k=3
pred = [int(sum(lyst[start:start+k]) >= k/2)
for start in range(0, len(lyst)-k)]
First you have an error in your code:
for x in range(0, len(lyst)-k) will iterate over the len(lyst)-k first items not the last ones.
You can read about range function to see how it works. Said that you can use slices in order to take the sum of the elements you want.
You code can be changed as:
for x in range(len(lyst) - 1, len(lyst) - k, -1):
sumList=sum(lyst[x-k:x])

Counting consecutive numbers in a list

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)

Controlling the flow of for loop in python

I'm trying to solve a musical chairs problem. The list_of_people is the list which contains the position of the people in the circle. The steps variable is the length of the song. So at each steps an element from list_of_people. At the end there should be only one element.I'm trying to solve this by using a simple for loop. I am deleting the elements in the loop at each steps that is at a count. I have two requirements: 1.)When I delete an element I want to step back one position in the loop from my current position. So, when I delete, I set the integer to the previous element, so the next time it should start from that position. But that's not working
2.) When the last element is reached i want to restart the for loop from the first position.
I know there is a provision in python itertools.cycle for cyclic iteration, but the problem in that is the len() function is not available and i'm breaking my for loop by checking the length of list_of_people
count=0
list_of_people = list(range(1,inputlength+1))
for integer in list_of_people:
if count==steps:
print("Element removed: "+str(integer))
#Getting the previous index
previous = list_of_people.index(integer)-1;
#deleting the current element
del list_of_people[list_of_people.index(integer)]
#Setting the index to previous element, THIS IS NOT WORKING!
#Need some help here!!!!!
integer = list_of_people[previous]
count=0
if len(list_of_people) < 2:#This is the breaking condition
break
#I need some help here!!!
#I need to restart the for loop from the first position
if list_of_people.index(integer)==len(list_of_people)-1:
#Set the loop index to zero
count+=1
print("The remaining element: "+str(list_of_people[0]))
Can anyone please help me on this? If there are any mistakes in the code, please forgive me I'm new to python.
It is extremely unwise to try to delete things from a list while you're iterating over it. Instead, build a new list, for example with a list comprehension:
list_of_people = [p for i, p in enumerate(list_of_people) if (i + 1) % steps]
An quick example:
>>> people = range(10)
>>> [p for i, p in enumerate(people, 1) if i % 3]
[0, 1, 3, 4, 6, 7, 9]
Based on your clarifying comments, I think what you want is simply:
def musical_chairs(people, steps):
index = 0
people = list(people)
while len(people) > 1:
index = (index + steps) % len(people)
del people[index]
index -= 1
return people
Demo:
>>> musical_chairs(range(1, 11), 4)
[6]

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