Having the following code:
def choose_sets(lst,k):
if k == 0:
return [[]]
if len(lst) == k:
return [lst]
else:
return choose_sets(lst[1:],k)+[[lst[0]]+i for i in choose_sets(lst[1:],k-1)]
How does i for i in choose_sets(lst[1:],k-1) work? Is it possible to give up on the loop and instead to write this?
+[[lst[0]]+choose_sets(lst[1:],k-1)]
this function returns list that contains all the different lists at length K that can be created out of the original list's members (the order isn't important)
i for i in choose_sets(lst[1:],k-1)
yields all the sets whose length is k-1 and does not contain lst[0]. In the other word, we got a list, whose elements are lists with length k-1. Adding lst[0] to each of them, we got all K-length sets that contains lst[0].
Plus choose_sets(lst[1:],k), which yields all K-length sets that does not contain lst[0], we got all
K-length sets.
Is it possible to give up on the loop and instead to write this?
No. +[[lst[0]]+choose_sets(lst[1:],k-1)] yields a list whose first element is with length 1 and all other elements are with length k-1, this is obviousely what we expected.
Related
So I was trying to complete this kata on code wars and I ran across an interesting solution. The kata states:
"Given an array of integers, find the one that appears an odd number of times.
There will always be only one integer that appears an odd number of times."
and one of the solutions for it was:
def find_it(seq):
return [x for x in seq if seq.count(x) % 2][0]
My question is why is there [0] at the end of the statement. I tried playing around with it and putting [1] instead and when testing, it passed some tests but not others with no obvious pattern.
Any explanation will be greatly appreciated.
The first brackets are a list comprehension, the second is indexing the resulting list. It's equivalent to:
def find_it(seq):
thelist = [x for x in seq if seq.count(x) % 2]
return thelist[0]
The code is actually pretty inefficient, because it builds the whole list just to get the first value that passed the test. It could be implemented much more efficiently with next + a generator expression (like a listcomp, but lazy, with the values produced exactly once, and only on demand):
def find_it(seq):
return next(x for x in seq if seq.count(x) % 2)
which would behave the same, with the only difference being that the exception raised if no values passed the test would be IndexError in the original code, and StopIteration in the new code, and it would operate more efficiently by stopping the search the instant a value passed the test.
Really, you should just give up on using the .count method and count all the elements in a single pass, which is truly O(n) (count solutions can't be, because count itself is O(n) and must be called a number of times roughly proportionate to the input size; even if you dedupe it, in the worst case scenario all elements appear twice and you have to call count n / 2 times):
from collections import Counter
def find_it(it):
# Counter(it) counts all items of any iterable, not just sequence,
# in a single pass, and since 3.6, it's insertion order preserving,
# so you can just iterate the items of the result and find the first
# hit cheaply
return next(x for x, cnt in Counter(it).items() if cnt % 2)
That list comprehension yields a sequence of values that occur an odd number of times. The first value of that sequence will occur an odd number of times. Therefore, getting the first value of that sequence (via [0]) gets you a value that occurs an odd number of times.
Happy coding!
That code [x for x in seq if seq.count(x) % 2] return the list which has 1 value appears in input list an odd numbers of times.
So, to make the output as number, not as list, he indicates 0th index, so it returns 0th index of list with one value.
There is a nice another answer here by ShadowRanger, so I won't duplicate it providing partially only another phrasing of the same.
The expression [some_content][0] is not a double list. It is a way to get elements out of the list by using indexing. So the second "list" is a syntax for choosing an element of a list by its index (i.e. the position number in the list which begins in Python with zero and not as sometimes intuitively expected with one. So [0] addresses the first element in the list to the left of [0].
['this', 'is', 'a', 'list'][0] <-- this an index of 'this' in the list
print( ['this', 'is', 'a', 'list'][0] )
will print
this
to the stdout.
The intention of the function you are showing in your question is to return a single value and not a list.
So to get the single value out of the list which is built by the list comprehension the index [0] is used. The index guarantees that the return value result is taken out of the list [result] using [result][0] as
[result][0] == result.
The same function could be also written using a loop as follows:
def find_it(seq):
for x in seq:
if seq.count(x) % 2 != 0:
return x
but using a list comprehension instead of a loop makes it in Python mostly more effective considering speed. That is the reason why it sometimes makes sense to use a list comprehension and then unpack the found value(s) out of the list. It will be in most cases faster than an equivalent loop, but ... not in this special case where it will slow things down as mentioned already by ShadowRanger.
It seems that your tested sequences not always have only one single value which occurs an odd number of times. This will explain why you experience that sometimes the index [1] works where it shouldn't because it was stated that the tested seq will contain one and only one such value.
What you experienced looking at the function in your question is a failed attempt to make it more effective by using a list comprehension instead of a loop. The actual improvement can be achieved but by using a generator expression and another way of counting as shown in the answer by ShadowRanger:
from collections import Counter
def find_it(it):
return next(x for x, cnt in Counter(it).items() if cnt % 2)
I am implementing a method in my python program that checks if a mathematical function is valid.
An example of one in my program would be:
['set',['tuple',1,2],['tuple',3,4]]
Which equates to, {(1,2),(3,4)}
For the check to return True all tuples within the set must have a unique number as their leftmost value. So the function {(1,2),(1,4)} would return false.
Currently I have implemented this for a set with one tuple, which would require no check for a unique value in the tuple:
if "set" in argument:
print("Found a set")
print("Next part of argument", argument[1])
if "tuple" in argument[1]:
print("Found a tuple, only one found so this argument is a function")
I am unsure how to implement this for a set that may contain multiple tuples like the examples above.
How about this:
def is_function(thing):
if thing[0] == 'set':
different = len(set(element[1] for element in thing if element[0] == 'tuple'))
tuples = sum(1 for element in thing if element[0] == 'tuple')
return different == tuples
If the first element is 'set', then count the number of different first items in the tuples (by measuring the length of its set), and compare it with the amount of "tuples" in the list.
>>> is_function(['set',['tuple',1,2],['tuple',3,4]])
True
>>> is_function(['set',['tuple',1,2],['tuple',1,4]])
False
Better explanation:
The function first tests whether the first element of the list is "set", if it's not the function terminates (and returns None).
A set is created from the generator comprehension element[1] for element in thing if element[0] == 'tuple', which will be the set of all second elements of all those lists in the main list that have a first element called "tuple". This set will contain all first values, each of them once (because it's a set).
The cardinality of that set is stored in different. It is the amount of different elements directly after "tuple".
A sum is calculated from a similar generator comprehension. Again, this iterates over all sublists whose first element is "tuple", but what is added up is just the number 1, therefore the result will be the amount of sublists that start with "tuple".
The function returns the result of different == tuples; so True if they're the same and False otherwise. If there are several "tuples" with the same starting element, then different will be smaller than tuples, so it will return False. If there aren't, it will return True, because the number of "tuples" with different starting elements will be the same as the number of "tuples".
Define a recursive function named sort; it is passed any unordered list; it returns a new list (not mutating the argument) that contains every value in the argument list, but in non-descending order.
For example, calling sort([4,5,3,1,6,7,2]) would call sort recursively on the lists [4,5,3]and [1,6,7,2], returning the lists [3,4,5] and [1,2,6,7] respectively, which when merged would be return the list [1,2,3,4,5,6,7].
Note when the length of the list is even, both sublists will have the same
size; when the length of the list is odd, it is natural to divide it into two lists, the first of which has one fewer values than the second.
The function starts like this:
def sort(l):
I know how to separate l into two list, for example [4,5,3,1,6,7,2], I separate them into [4,5,3] and [1,6,7,2]. But I really don't know how to recursively sorting each half when the sort function only has one argument l.
Can someone please tell the way to do this? Thank you.
I gave it a go and it seems to work. Like TobiasR said, it's a merge sort. If you want a better explanation of how it works, I'd check out this video on merge sorts by Harvard University.
Anyway, this is the code for it:
def sort(l):
if len(l)==2:
if l[0]<l[1]:
return l #return list as it is
return l[::-1] #return reversed list
elif len(l)==1:
return l
l_1=sort(l[:len(l)//2]) # cut the list in half
l_2=sort(l[len(l)//2:])
l_out=[]
while True:
if not l_1: #check l1 isn't empty
l_out+=l_2
break;
elif not l_2: #check l2 isn't empty
l_out+=l_1
break;
if l_1[0]<l_2[0]: #put the smallest item in the list
l_out.append(l_1.pop(0))
else:
l_out.append(l_2.pop(0))
return l_out
So, there is a list like
list=["one","two","ne","three"....]
I wonder, how do I compare each element of the list with others by using endswith() method?
in this list, for example, list[0] endwith list[2].
I couldn't get how to make a comparison itself.
I'm trying something like:
aa=list
flg=False
for i in range(len(ll)-1):
aa.append(ll[i+1])
if ll[i].endswith(aa[i]):
flg=True
however, it's good only for the first element, not with each one.
Using sets:
words = {"one","two","ne","three"}
[x for x in words if any(word.endswith(x) for word in words - {x})]
Out[69]: ['ne']
Basically, for each element, remove it from the words set, and then test if any of the other words in the truncated set end with that word.
You are only doing a single pass through the list, even though you have stated your goal as "Compare each element of the list with the others". This necessitates making one traversal of the list per element in the list. If you have n items, you will traverse the list n times for every item, for a total of n^2 traversals.
Hence, you need two for loops in your solution: one to traverse the list once and select the element that will be compared, and inside that loop, another that will check that element against the others.
for n in ll:
for m in ll:
if m.endswith(n) and m != n:
print(m, "ends with", n)
I'm asked to create a method that returns the number of occurrences of a given item in a list. I know how to write code to find a specific item, but how can I code it to where it counts the number of occurrences of a random item.
For example if I have a list [4, 6 4, 3, 6, 4, 9] and I type something like
s1.count(4), it should return 3 or s1.count(6) should return 2.
I'm not allowed to use and built-in functions though.
In a recent assignment, I was asked to count the number of occurrences that sub string "ou" appeared in a given string, and I coded it
if len(astr) < 2:
return 0
else:
return (astr[:2] == "ou")+ count_pattern(astr[1:])
Would something like this work??
def count(self, item):
num=0
for i in self.s_list:
if i in self.s_list:
num[i] +=1
def __str__(self):
return str(self.s_list)
If this list is already sorted, the "most efficient" method -- in terms of Big-O -- would be to perform a binary search with a count-forward/count-backward if the value was found.
However, for an unsorted list as in the example, then the only way to count the occurrences is to go through each item in turn (or sort it first ;-). Here is some pseudo-code, note that it is simpler than the code presented in the original post (there is no if x in list or count[x]):
set count to 0
for each element in the list:
if the element is what we are looking for:
add one to count
Happy coding.
If I told you to count the number of fours in the following list, how would you do it?
1 4 2 4 3 8 2 1 4 2 4 9 7 4
You would start by remembering no fours yet, and add 1 for each element that equals 4. To traverse a list, you can use a for statement. Given an element of the list el, you can check whether it is four like this:
if el == 4:
# TODO: Add 1 to the counter here
In response to your edit:
You're currently testing if i in self.s_list:, which doesn't make any sense since i is an element of the list and therefore always present in it.
When adding to a number, you simply write num += 1. Brackets are only necessary if you want to access the values of a list or dictionary.
Also, don't forget to return num at the end of the function so that somebody calling it gets the result back.
Actually the most efficient method in terms of Big-O would be O(log n). #pst's method would result in O(log n + s) which could become linear if the array is made up of equal elements.
The way to achieve O(log n) would be to use 2 binary searches (which gives O(2log n), but we discard constants, so it is still O(log n)) that are modified to not have an equality test, therefore making all searches unsuccessful. However, on an unsuccessful search (low > high) we return low.
In the first search, if the middle is greater than your search term, recurse into the higher part of the array, else recurse into the lower part. In the second search, reverse the binary comparison.
The first search yields the right boundary of the equal element and the second search yields the left boundary. Simply subtract to get the amount of occurrences.
Based on algorithm described in Skiena.
This seems like a homework... anyways. Try list.count(item). That should do the job.
Third or fourth element here:
http://docs.python.org/tutorial/datastructures.html
Edit:
try something else like:
bukket = dict()
for elem in astr:
if elem not in bukket.keys():
bukket[elem] = 1
else:
bukket[elem] += 1
You can now get all the elements in the list with dict.keys() as list and the corresponding occurences with dict[key].
So you can test it:
import random
l = []
for i in range(0,200):
l.append(random.randint(0,20))
print l
l.sort()
print l
bukket = dict()
for elem in l:
if elem not in bukket.keys():
bukket[elem] = 1
else:
bukket[elem] += 1
print bukket