Looping with Consecutive Elements - python

I'm a beginner in Python programming and I'm having some trouble with some list stuff.
So I want to write a function that returns a boolean value. The function will inform the user whether there is a duplicate consecutive pair of elements in the list he or she entered. By the way, I want to do this using only len(), range(), loops, if-statements, variables and arithmetic (no built in functions).
For example:
contains_consecutive_duplicates([1,3,3]) should return True
contains_consecutive_duplicates([3,2,3]) should return False
My code:
def contains_consecutive_duplicates(xs):
for i in xs:
if xs[i] == xs[i-1] or xs[i] == xs[i+1]:
return True
else:
return False
My logic to this was as follows: Each time the for loop would run, i would refer to some element in the list. If that element was such that the element before it or after it was equal to it, then the for loop would return true. If not, keep searching. If there are none, it would return false.
Now, I actually understand where the error is (I think). The problem is that I don't know how to solve it. I think the for loop is running into a problem at the beginning (when i is reffering to the 0th element). There is no element before the 0th element, hence the error:
"index out of range"
P.S: Is that how you return a boolean value?
Is there a better way to do this?
I would appreciate any help given! Thanks in advance!

#roeland pointed out the problem with assuming iterating the list directly would get you indices (if you want index and value, use enumerate). But in this case you don't actually need the index.
For the simple case (where it's known to be a container you can slice), you can just iterate with zip over offset slices:
def contains_consecutive_duplicates(xs):
return any(x == y for x, y in zip(xs, xs[1:]))
More general solutions can be made with itertools.groupby to handle the case where you can't slice, but this is simple and involves no imports.
Use of any in this case is just a short hand to slurp the generator expression and return True if any values are truthy. The long equivalent form is:
def contains_consecutive_duplicates(xs):
for x1, x2 in zip(xs, xs[1:]):
if x1 == x2:
return True
return False
Since your teacher apparently thinks built-ins are bad, but len and range aren't built-ins (they are), you can do this the dumb way:
def contains_consecutive_duplicates(xs):
for i in range(len(xs) - 1):
if xs[i] == xs[i+1]:
return True
return False
Which does the same work as ziping, just less efficiently (generating index integers and explicitly indexing is surprisingly expensive in Python relative to native iteration).

This should do:
>>> def contains_consecutive_duplicates(xs):
... for i, v in enumerate(xs[:-1]):
... if v == xs[i+1]:
... return True
... else:
... pass
... return False
>>> l1 = [1,3,3]
>>> l2 = [1,3,2]
>>> l3 = []
>>> l4 = [2]
>>> contains_consecutive_duplicates(l1)
True
>>> contains_consecutive_duplicates(l2)
False
>>> contains_consecutive_duplicates(l3)
False
>>> contains_consecutive_duplicates(l4)
False
>>>

By using only range, for and if statements, this can be done with:
def contains_consequtive_duplicates(xs):
for i in range(len(xs)-1):
if xs[i] == xs[i+1]: return True
return False
You access lists with their index and not by their value (which you are by using for i in list). Additionally, if you perform the check xs[i] == xs[i-1] this will not yield the result you want since x[-1] will check the end of the list so [3, 2, 3] will return True.
As a small demonstration:
if contains_consequtive_duplicates([1,3,3]): print "consecutive"
# Prints Consequtive
if contains_consequtive_duplicates([3, 2, 3]): print "consecutive"
# Prints nothing

Try this:
def contains_consecutive_duplicates(xs):
for i in xs:
if xs.indexOf(i)==len(xs):
break
if xs[i] == xs[i-1] or xs[i] == xs[i+1]:
return True
else:
return False
What you are doing is trying to do is evaluate xs[i+1], but that does not exist.

This should do the trick:
def contains_consecutive_duplicates(xs):
for i in range(1, len(xs) - 1):
if xs[i] == xs[i-1] or xs[i] == xs[i+1]:
return True
return False
It iterates through all values bar the first and last (created by the range function), returning (which ends the loop) if it finds a duplicate.
If it reaches the end and hasn't found a duplicate one must not exist, so it returns False.

Related

How to find if there are 2 elements of same value consecutively in a list?

For example,
[1,3,3,5] should return True while [1,3,1,3] should return False.
I am looking for a simple solution using loops.
I tried the following:
def conseq(nums):
for i in range (len(nums)):
if nums[i]==nums[i+1]:
return True
break
else:
return False
The first time your function encounters 2 consecutive numbers which are different, it returns False. Returning from a function ends that function immediately, the function does not continue after that. This is also why the break is not necessary.
Another issue with your code is that once you reach the final number, nums[i + 1] will access out of the bounds of the array. That's why you should iterate over len(nums) - 1 rather than len(nums) - there's no reason to check the final number because there's nothing after it.
def conseq(nums):
for i in range(len(nums) - 1):
if nums[i]==nums[i+1]:
return True
# Only return False once we've exhausted all numbers.
# Since we didn't return True so far - it means there are
# no consecutive equal numbers, so we can safely return False
return False
the return ends the function, so here it will stop the processing as well
your true statement mostly works, and the break is unnecessary
you don't want the else statement until after the for loop ends (it returns False only if everything else has been parsed)
Also the way you parse through the code, nums can't access nums[i+1] when you're at the final nums so you need the range len(nums) - 1
If you feel like putting an else that does nothing, you can with a single semicolon or pass I believe, but the else is unnecessary here
def conseq(nums):
for i in range (len(nums)-1):
if nums[i]==nums[i+1]:
return True
else:
;
return False
You can't return False until the loop is done (since the match may be in the part of the list you haven't checked yet). And the break after return will never happen (since return ends the function and everything in it).
Enumerate list without last (to avoid try catch for i+1 being out of range) then compare each item with next one and return True if they are same. After loop return False because none are similar consequtively (returns break functions)
def function(number_list):
for i, item in enumerate(number_list[:-1]):
if item == number_list[i+1]:
return True
return False
def conseq(nums):
for i in range (len(nums)):
if nums[i]==nums[i-1]:
return True
return False
I modified your Code. Please check and let know if useful
def conseq(nums):
flag=True
for i in range (len(nums)-1):
if nums[i]==nums[i+1]:
print(True)
flag=False
break
else:
continue
if(flag):
print(False)
nums=[1,3,3,5]
nums1=[1,3,1,3]
conseq(nums)
conseq(nums1)
We have many solutions here already. I have tried out using numpy without a loop:
>>> import numpy as np
>>> f = np.array([1,3,3,5])
>>> (np.where(np.diff(f) == 0)[0]).astype('bool')[0] #check if we have any difference of two elements 0?
True

Why is this code removing `False` from the array?

This is the task:
Write an algorithm that takes an array and moves all of the zeros to the end, preserving the order of the other elements
What is wrong with this code? Why is it not keeping boolean values while iterating through the list and removing zeros? Is it because False is equal to 0?
move_zeros([False,1,2,0,1,0,1,0,3,0,1])
def move_zeros(array):
count=0
for num in array:
if num == 0:
count +=1
array.remove(0)
return array +[0]*count
Yes, False == 0 will evaluate to True in Python which is why False values are being removed from your array.
In Python, True and False are implemented as singletons, meaning all False values point to the same instance. Therefore, you can use the is operator to check if a value is exactly equal to this singleton.
False is 0 will return False, while False == 0 will return True.
x = len(lis)
y = []
for i in range(len(lis)):
if lis[i]!=0:
y.append(lis[i])
if len(y)!=len(lis):
z = len(lis)-len(y)
for i in range(z):
y.append(0)
Seems like its a homework problem. Happy to help tho.
Edit: use print(y) and you'll get what you want
Yes, indeed False == 0. Actually, bool is a subtype of int. If you want to strictly compare if False is equal to 0, then another comparison should be added to the if statement.
Also, do not modify a list while you are iterating over itself. Create a new one instead.
def move_zeros(list_):
result = []
zeros = 0
for item in list_:
if item == 0 and type(item) == int:
zeros += 1
continue
result.append(item)
return result + [0] * zeros
Yes 0 evaluates to False and 1 evaluates to True, use this
def move_zeros(obj):
new_list = []
zeros_list = []
for item in obj:
if item != 0 or is False:
new_list.append(item)
else:
zeros_list.append(item)
new_list.extend(zero_list)
return new_list
This adds all non 0 to one list and all 0's to another, then returns the new_list after iterating over the zeros_list and adding them to the end of the new_list
There are 2 issues in your code:
You directly changed the list over which you iterate — it is always dangerous.
Other answers explained to you why False == 0 is True.
I made as few changes in your code as it was possible to fix these issues:
I created a new, empty array, and instead of removing “bad” elements from the original list, I appended the “good” ones to that new array.
I tested a current element for its type, too.
def move_zeros(array):
count=0
new_array = []
for num in array:
if num == 0 and type(num) is int:
count +=1
else:
new_array.append(num)
return new_array + [0]*count
Test:
move_zeros([False,1,2,0,1,0,1,0,3,0,1])
[False, 1, 2, 1, 1, 3, 1, 0, 0, 0, 0]

Python, check whether array elements are all same or not

I have an array, say [4 4 4 4 4], here the length is 5. In real case it could be 300. How to check whether all the elements are same, say in this case all are 4. If all elements have same value, the function return true, otherwise false. The element could be only interger and value could be either one of them: 0,1,2,3,4.
I could use a loop in Python as follows. But I am looking for a concise way or simple way to do that, say one line.
x= [4,4,4,4]
temp = x[0]
for ele in x:
if(temp != ele):
false
true
You can put elements into set() and then check if length of the set is equal to 1:
if len(set(x)) == 1:
print('All elements are same')
else:
print('Not same')
it might be more efficient not to iterate over the full list (as does the set constructor) but to stop at the first element that does not equal x0. all does that for you:
x = [4,4,4,4]
x0 = x[0]
print(all(item == x0 for item in x))
# True
this is basically the same version you had; only the loop will be much more efficient this way.
also note that true and false are not valid python identifiers. in python it is True and False.

How do I tell if a list is in ascending order? Just needs to return True or False

The way I have it it stops after checking if the first two digits are ascending.
How do I make it keep running until it has checked the whole list?
def isAscending(xs):
for n in range(len(xs) + 1):
if xs[n] > xs[n+1]:
return False
else:
if xs[n] < xs[n+1]:
return True
Only return True at the end, that is after every element has been checked. Fixing your code with minimal changes:
def isAscending(xs):
for n in range(len(xs) - 1):
if xs[n] > xs[n+1]:
return False
return True
print isAscending([1,2,3,4]) # True
print isAscending([1,2,4,3]) # False
Short solution:
>>> lst = [1,2,3,4]
>>> sorted(lst) == lst
True
>>> lst = [1,2,4,3]
>>> sorted(lst) == lst
False
Better short solution that runs in O(n) (sorting is O(n log n)):
>>> lst = [1,2,3,4]
>>> all(x <= y for x,y in zip(lst, lst[1:]))
True
>>> lst = [1,2,4,3]
>>> all(x <= y for x,y in zip(lst, lst[1:]))
False
To make the last one more memory efficient, use itertools.izip in place of zip if you are using Python 2.
Just keep track of the previous one:
def isAscending(xs):
prev = None
for n in xs:
if prev is not None and n < prev:
return False
prev = n
return True
Use the Python built-in all operator to do the optimization and iteration for you. The following code says "Let me know if everything in the list is True." It will quit early if it finds a False value.
def isAscending(xs):
return all([xs[n] <= xs[n+1] for n in range(len(xs)-1)])
For future reference, the or version of this is the any operator.
Just have it return True if it isn't False! Whenever return is called, it breaks out of the function. Only one return is ever called.
def isAscending(xs):
for n in range(len(xs) + 1):
if xs[n] > xs[n+1]:
return False
return True
This way, if it is not in ascending order, then the function returns False and exits the function. If the return False is never activated, though, then the list must be in ascending order so the return True is activated.

Python Identifying Suffix within set of strings

doing an exercise on CheckIO and I'm wondering as to why this won't work. Given a set of strings, I'm trying to return True if any of the strings are suffixes of any other string in the set. False otherwise. Using itertools I'm generating the necessary permutations in tuples first. Then for each tuple (each i), I wanted to see the hard way if the second tuple was in the end of the first tuple (option1). The otherway was using the .endwith function (option2), but neither will work for me. Why are these two options flawed?
import itertools
def checkio(words_set):
for i in itertools.permutations(words_set, 2):
#option1 ---- if i[1] in i[0][-len(i[1]):]:
#option2 ---- if i[0].endswith(i[1]):
return True
else:
return False
examples:
checkio({"hello", "lo", "he"}) == True
checkio({"hello", "la", "hellow", "cow"}) == False
I know this works as an answer. But just wondering why my original methods wouldn't take.
def checkio(words_set):
for w1 in words_set:
for w2 in words_set:
if w1.endswith(w2) and w1 != w2:
return True
return False
Your return False should be at the end of the for loop, otherwise the function will return True/False at every first comparison and will ignore all subsequent comparisons:
import itertools
def checkio(words_set):
for i in itertools.permutations(words_set, 2):
if i[0].endswith(i[1]):
return True
return False
Since it's an exercise, I won't give you the full answer, but are you sure that you really want to return False in the else clause?
Its because you return False right after the first check. and if it fails it will returns False you need to put it out of your for loop!
But as a more pythonic way you can use combinations and a generator expression within any function :
>>> from itertools import combinations
>>> s={"hello", "lo", "he"}
>>> any(i.endswith(j) or j.endswith(i) for i,j in (combinations(s,2)))
True
>>> s2={"hello", "la", "hellow", "cow"}
>>> any(i.endswith(j) or j.endswith(i) for i,j in (combinations(s2,2)))
False

Categories

Resources