If a letter (string) is in a list,
find_letter(['o', ['hello', 'c', 'bye']),
return True, if not return False.
def find_letter(lst):
lst=['o','hello', 1]
n='o'
if not lst:
return 0
elif lst[0] == n:
return True
elif find_letter(lst[0:]):
return True
else:
return False
print(find_letter(lst))
It does return 'True', but I am not sure if this is the right way to do this. Maybe there's a better way? In the second elif-statement, is python going through all the elements in the list if the first one doesn't contain the letter? The function must be recursive.
I think the most pythonic approach would be to use
def find_letter(letter, lst):
return any(letter in word for word in lst)
The beauty of this is that it iterates over lst and returns as soon as one of the words in that list contains letter. Also, it doesn't need to recurse.
This returns False instead of 0 if lst is empty, though (unlike your program) but since False evaluates to 0 anyway (and vice versa), that's not really an issue.
Since you need a recursive version:
Short version
def find_letter(let, lst):
return (lst or False) and \
((isinstance(lst[0], str) and let in lst[0]) or find_letter(let, lst[1:]))
More explicit version
def find_letter(let, lst):
if lst:
e = lst[0]
return (isinstance(e, str) and let in e) or find_letter(let, lst[1:])
return False
Even more explicit version
def find_letter(let, lst):
if lst:
e = lst[0]
if isinstance(e, str) and let in e:
return True
return find_letter(let, lst[1:])
return False
Note that I leave out a couple of else: because they are not necessary after a return statement. If you don't want to test for a letter in a string, but just for equality, replace let in ... by let == ....
Here is your error
def find_letter(lst): # You receive your list as lst
lst=['o','hello', 1] # Opppsss! You override it. It does not matter what you receive with lst above, now its value is ['o','hello', 1]
n='o'
So in find_letter(lst[0:]), you use list slicing, but on lst=['o','hello', 1] line, you override it again and you always execute your search on the first element of the list.
n = "o" # you can set this too, but this is optional
def find_letter(lst):
# do not set a value to lst in here
if not lst:
return 0
elif lst[0] == n: # You checked first element in here
return True
elif find_letter(lst[1:]): # since you checked the first element, skip it and return the orher elements of the list
return True
else:
return False
lst = ['o','hello', 1]
print find_letter(lst)
You want to find the Membership
Please refer this code to resolve your problem.
Suppose
list1 = ['physics', 'chemistry', 1997, 2000];
list2 = [1, 2, 3, 4, 5, 6, 7 ];
print "list1[0]: ", list1[0]
print "list2[1:5]: ", list2[1:5]
print 3 in list2
Output:
list1[0]: physics
list2[1:5]: [2, 3, 4, 5]
True
Just realized OP wants to check A string only
You can define a function and match the string in a list recursively like this:
def plist(lst, n):
# loop inside the list
for each in lst:
# if "each" is also a list (nested), check inside that list, too
if isinstance(each, list):
# this will reuse your "plist" and loop over any nested list again
plist(each, n)
# if n matches any element in the list, return True
if any(n in each_letter for each_letter in each):
return True
# if after looping over your list + nested list, return False if no match is find
else:
return False
>> lst = ['o', ['hello', 'c', 'bye']]
>> plist(lst, 'o')
>> True
>> plist(lst, 'h')
>> True
>> plist(lst, 'z')
>> False
Hope this solves your problem.
Here is a one line lambda:
any(list(map(lambda x: True if n in str(x) else False,lst )))
data:
lst=['o','hello', 1]
n='o'
output 1:
True
note:
any() checks if any True, then True - otherwise False - so without the any() we get:
list(map(lambda x: True if n in str(x) else False,lst ))
output 2:
[True, True, False]
Related
I'm trying to build a function that prints true if the tuples, lists and strings inputted are sorted, and False if not. I've tried two different methods but neither worked.. Could anyone tell me what part is wrong? Thank you !!!
def is_ordered (*args):
for i in range(1,len(args)):
if args[i - 1] > args[i]:
return True
else:
return False
def is_ordered (*args):
if args == args.sorted()
return True
else:
return False
Here are the lists and tuples I created.
sorted_list = [1,2,3,4,5,6,7]
is_ordered(sorted_list)
unsorted_list = [41,3,35,4,45,6,7]
is_ordered(unsorted_list)
sorted_tuple = (1,2,3,4,5,6,7)
is_ordered(sorted_tuple)
unsorted_tuple = (41,3,35,4,45,6,7)
is_ordered(unsorted_tuple)
stri = "datascience"
is_ordered(stri)
You don't actually need to sort the input to tell if it's sorted. You just need to see if each item is less than or equal to the item before it and return False if that's ever not the case. This will be more efficient than sorting, then checking.
You can compare items with the neighbor by zipping the list with itself at an offset like zip(seq, seq[1:].
def is_ordered (seq):
'''Return true if every item is less than or equal the item after it'''
return all(a <= b for a, b in zip(seq, seq[1:]))
is_ordered('abcd')
#True
is_ordered('abdag')
#False
is_ordered([1, 2, 3, 4])
#True
If you want to use sorted(), don't use *args just accept a sequence as an argument and understand that sorted(someString) will not equal a string because it makes a list. So you need to compare like things:
def is_ordered (seq):
return list(seq) == sorted(seq)
is_ordered((1, 2, 3))
#True
is_ordered((1, 2, 3, 0))
#False
is_ordered("abcd")
# True
is_ordered("abcda")
# False
This question already has answers here:
Finding subsequence (nonconsecutive)
(4 answers)
Closed 3 years ago.
I have a list and want to check if a given sequence exist in the list or not. For example the given sequence is 'a','h','z' and the list is l = ['a','b','h','g','z']. Given that in the list z comes after h after a, I need the code returns True value.
def check_for_a_h_z(seq):
return ('a','h','z') in zip(seq, seq[1:], seq[2:])
The code return true if only 'a','h','z' are coming exactly after each other.
Back of the envelope brute force attempt at a generic solution for two sequences:
from typing import Sequence
def ordered_contains(s1: Sequence, s2: Sequence) -> bool:
'''
>>> ordered_contains('ahz', 'abhgz')
True
>>> ordered_contains('', 'asdlkjf')
True
>>> ordered_contains('lol', 'lofi')
False
'''
i = 0
for v in s1:
try:
i = s2.index(v, i)
except ValueError:
return False
return True
This will return True if things is somehwere in order in seq in O(n) worst case:
def check_for_things(things,seq):
k = things[:]
for c in seq:
if c == k[0]:
k.pop(0)
if not k:
break
return not k # if you popped all from k you are done
print( check_for_things(list("ahz"), list('abhgz')))
print( check_for_things(list("ahiz"), list('abhgz')))
Output:
True
False
It will also produce True for list("ahz"), list('abhhhhhhhhhhgz') - the superflous h are ignored.
A more optimized solution (suggested by #Aran-Frey) would be using deque - popping elements anywhere then the end of a list is costly because the whole remaining list data is shifted over by 1 - deque can popleft (and popright) in O(1):
def better_check_for_things(things,seq):
k = deque(things)
for c in seq:
if c == k[0]:
k.popleft()
if not k:
break
return not k # if you popped all from k you are done
print( better_check_for_things(list("ahz"), list('abhgz')))
print( better_check_for_things(list("ahiz"), list('abhgz')))
Here's a way to do it with recursion:
def list_sequence_recursive(test, lst):
if len(test) == 1:
return test[0] in lst
else:
if test[0] in lst:
idx = lst.index(test[0]) + 1 # don't send the matched element
return list_sequence_recursive(test[1:], lst[idx:])
else:
return False
test_sequence_recursive(['a', 'h', 'z'],
['a','b','h','g','z'])
# True
Note we use lst.index(test[0]) + 1 for the next iteration's starting index so that we only send elements after the one that was matched. If you leave off the + 1, you would erroneously match your input list with, say ['a', 'a', 'h'] even though you only have one 'a'.
For your example, this would:
find 'a' and then call itself with the arguments ['h', 'z'] and ['b','h','g','z']
find 'h' and then call itself with the arguments ['z'] and ['g', 'z']
find 'z' and return True up the chain
A somewhat intuitive way to do it, but not very Pythonic:
l=['a','b','h','g','z']
def check_for_a_h_z(seq):
if 'a' in seq:
ind=seq.index('a')
if 'h' in seq[ind:]:
ind2=seq.index('h')
if 'z' in seq[ind2:]:
return True
else:
return False
else:
return False
else:
return False
check_for_a_h_z(l)
I've been stuck on this for a while and I keep running into problems, I'm trying to create a function that returns true if at least one pair of adjacent elements in a list are equal.
Test cases:
[1, 2, 3] -> False
[1, 2, 2, 3] -> True
[2, 6, 3, 6] -> False
['a', 'b', 'c', 'd', 'd'] -> True
def equal_adjacent_elements(l):
for x in range(len(l)):
if l[x] == l[x+1] or l[x] == l[x-1]:
return True
else:
return False
The problems I run into are assertion errors and I believe it's because of my loop. Once I find a pair that is equal the returned value won't stay the same because my loops will evaluate the next values in the list. So I just need to find at least one pair, I don't know how I would do that though.
You can zip the list with itself offest by 1 and use any to short-cut the find-one pattern:
def equal_adjacent_elements(l):
return any(x == y for x, y in zip(l, l[1:]))
I made few changes. It should work now.
def equal_adjacent_elements(l):
for x in range(len(l)-1):
if l[x] == l[x+1]:
return True
return False
or, shorter one using any,
def equal_adjacent_elements(l)
return any( l[x] == l[x+1] for x in range(len(l)-1) )
There are two problems here:
the indices can run into overflow here;
you immediately return False from the moment there are two consecutive elements that are not equal, you should return False after the for loop.
The index problem here is that x ranges from 0 to (excluding) len(l). So that means x-1 ranges from -1 (which is the last element of the list) to len(l)-1 and x+1 from 1 to len(l) (including). But the list is not that long, so you get an index out of the list bounds, which is an error.
A more Pythonic approach however is to use a zip(..) over the list l, and the "tail" of the list (the list omitting the first element). So zip(l, l[1:]).
We can iterate over every pair x,y of l and l[1:]. In case x == y, then we have such element and return True.
In case we fail to find such pair, we eventually return `False.
So a correct implementation is:
def equal_adjacent_elements(l):
for x,y in zip(l, l[1:]):
if x == y:
return True
return False
Python however has a builtin any, that will return True from the moment the iterable we give it contains at least one True; and False if no element has truthiness True.
So we can convert the above code to something using the any builtin:
def equal_adjacent_elements(l):
return any(x == y for x,y in zip(l, l[1:]))
I'm kinda new to python but anyways hoped this is easy enough
def equal_adjacent_elements(l):
try:
for i in range(0, len(l)):
if l[i] == l[i+1]:
return True
except IndexError:
return False
As an exercise, I'm creating a code which recursively sums the elements of a list, including lists within lists.
Sample list: a = [1,2,[3,4],[5,6]]
Sample result: 21
My code is as follows:
a = [1,2,[3,4],[5,6]]
def sum(list):
if len(list[0]) == 1 and len(list) ==1: # case where list is [x]
return list[0]
elif len(list[0]) == 1 and len(list) > 1: # case where list is [x, etc]
return list[0] + sum(list[1:])
elif len(list[0]) > 1 and len(list == 1): # case where list is [[x,etc]]
return sum(list[0])
else: # case where list is [[x, etc], etc]
return sum(list[0]) + sum(list[1:])
print (sum(a))
However, when I try to run this I get the error "object of type 'int' has no length." I was under the impression that list[0] would just have a length of 1 if it's not a list in itself, but obviously, that doesn't work. What should I be doing instead to check whether an element in a list is itself a list?
What should I be doing instead to check whether an element in a list is itself a list?
if isinstance(x, list):
Common Gotchas You shouldn't name your own variables as list because you then overwrite the type list and function list()
Similarly for your function sum(). You wouldn't want to overwrite the sum() function that already handles a list of numbers.
Or another way would be hasattr(lst, "__len__")
from numbers import Number
def recur_sum(lst):
# Return single value immeadiately
if not lst or lst is None:
return 0
if isinstance(lst, Number):
return lst
head = None
tail = False
if hasattr(lst, "__len__"):
_size = len(lst)
if _size <= 0: # case where list is []
head = 0
elif _size >= 1:
if hasattr(lst[0], "__len__"): # case where list is [[x,etc]]
head = recur_sum(lst[0])
else: # case where list is [x]
head = lst[0]
tail = (_size > 1)
if not tail:
return head
else:
return head + recur_sum(lst[1:])
In short, you may use the isinstance function to check if an element is a list or not.
The follwoing code may serve as an example.
a = [1,2,[3,4],[5,6]]
a
Out[3]:
[1, 2, [3, 4], [5, 6]]
isinstance(a,list)
Out[4]:
True
isinstance(a[0],list)
Out[5]:
False
isinstance(a[2],list)
Out[6]:
True
For an item in the list you may change the if condition to if type(item) is list:
a = [1,2,[3,4],[5,6]]
for item in a:
if type(item) is list:
# do_something_with(item)
print(item)
and the output will look like this:
[3,4]
[5,6]
Make sure the reserved word list is not overwritten as a variable!
I have a list say p = [1,2,3,4,2]
Is there any way of returning bool value True if it contains a duplicate using only find, indexing, slicing, len() etc methods and not dict, tuple etc.
I used this code:
for e in p:
duplicate = p.find(e, e+1)
if duplicate in p:
return True
Here is the easy way:
return len(p) != len(set(p))
A less efficient way that doesn't use set:
for i in range(len(p)):
if p[i] in p[i+1:]:
return True
return False
This second approach is not very idiomatic, but avoids all but the most basic features of the language (including tuples).
Here is one more way:
while p:
e = p.pop()
if e in p:
return True
return False
This is simple, but does modify the list.
One final way I am going to demonstrate is:
s = sorted(p)
for i in range(1, len(s)):
if s[i] == s[i - 1]:
return True
return False
This works by sorting p and then comparing every pair of consecutive elements.
You could also use list.count:
def has_duplicates(p):
for e in p:
if p.count(e) > 1:
return True
return False
>>> p = [1, 2, 3, 4, 2]
>>> len(set(p)) == len(p)
False
You can find more information about sets in the Python Documentation.
If you have to do it this way, you could do:
def has_duplicates(lst):
for i, e in enumerate(lst[::-1]):
if lst.index(e) != len(lst) - i - 1:
return True
return False
This iterates through the list in reverse order (since index searches from the start of the list). But it's better simply to do:
def has_duplicates(lst):
return len(set(lst)) != len(lst)
Using collections.Counter
>>> import collections
>>> p
[1, 2, 3, 4, 2]
>>> if collections.Counter(p).most_common()[0][1] > 1:
... print('duplicate found')
...
duplicate found
>>> if collections.Counter(set(p)).most_common()[0][1] > 1:
... print('duplicate found')
...
>>>
Here's a very simple way to do it. It may be slow for very large lists.
def has_duplicates(lst):
for e in lst:
lst = lst[1:]
if e in lst: return True
return False