Python counting elements of a list within a list - python

Say I have the following list:
L=[ [0,1,1,1],[1,0,1,1],[1,1,0,1],[1,1,1,0] ]
I want to write a code will take a list like this one and tell me if the number of '1s' in each individual list is equal to some number x. So if I typed in code(L,3) the return would be "True" because each list within L contains 3 '1s'. But if I entered code(L,2) the return would be "False". I'm new to all programming, so I'm sorry if my question is hard to understand. Any help would be appreciated.

To see if each sublist has 3 1's in it,
all( x.count(1) == 3 for x in L )
Or as a function:
def count_function(lst,number,value=1):
return all( x.count(value) == number for x in lst )
L=[ [0,1,1,1],[1,0,1,1],[1,1,0,1],[1,1,1,0] ]
print(count_function(L,3)) #True
print(count_function(L,4)) #False
print(count_function(L,1,value=0)) #True

Assuming your lists contain only 1's and 0's, you can count the ones quite easily: sum(sl). You can get the set of unique counts for sub-lists and test that they all have three 1's as follows:
set( sum(sl) for sl in L ) == set([3])
While a little obscure compared to using the all() approach, this method also lets you test that all sub-lists have the same number of ones without having to specify the number:
len(set( sum(sl) for sl in L )) == 1
You can even "assert" that the sub-lists must all have the same number of 1's and discover that number in one operation:
[n] = set( sum(sl) for sl in L )
This assigns the number of 1's in each sub-list to n, but raises a ValueError if the sub-lists don't all have the same number.

If L is your base list and n is the number of 1 you expect in each "sublist", then the check looks like this:
map(sum, l) == [n] * len(l)
The whole function, along with tests, looks like this:
>>> def check(l, n):
return map(sum, l) == [n] * len(l)
>>> L=[ [0,1,1,1],[1,0,1,1],[1,1,0,1],[1,1,1,0] ]
>>> check(L, 3)
True
>>> check(L, 2)
False
EDIT: Alternative solutions include for example:
map(lambda x: x.count(1), l) == [n] * len(l)
set(i.count(1) for i in l) == {n} (the most efficient within this answer)
but I believe the cleanest approach is the one given by one of the other answerers:
all(i.count(1) == n for i in l)
It is even pretty self-explanatory.

def all_has(count, elem, lst)
"""ensure each iterable in lst has exactly `count` of `elem`"""
return all(sub_list.count(elem) == count for sub_list in lst)
>>> L = [ [0,1,1,1],[1,0,1,1],[1,1,0,1],[1,1,1,0] ]
>>> all_has(3, 1, L)
True
>>> all_has(2, 0, L)
False

Related

Check if list is sublist of another list and the elements are in the same order

#sub list test 1
a = [1,1,2]
b = [0, 1,1,1,2,1]
#sub list test 2
c = [4,5]
d = [2,3,4,5,6]
if all(i in a for i in b):
print("Yes I have all the elements but not sure about their order :( ")
I have tried all() or using counter() from collections module. I can't seem to figure it out how to check their order too.
This will check all subList of length a and return True if a is found in b
Not sure about order :
def isSublist(a,b):
#checking all unique elements and their count
for i in set(a):
if i not in b or a.count(i) > b.count(i):
return False
return True
Sure about order :
def isSublist(a,b):
for i in range(len(b)-len(a)+1):
if b[i:i+len(a)] == a:
return True
return False
In most cases, when elements of lists has normal types, you can just convert them to str first and then do
"#".join(sublist) in "#".join(list)
Where # is a symbol that doesn't occur in list
Edit, as no comment pointed out, indeed there is one bug it that approach - if last sublists element is prefix of last lists element. Same with first element suffix. We can manage it by adding some kind of sentinel at the beggining/end, so correct solution would be
"#".join([""] + sublist + [""]) in "#".join([""] + list + [""])
You can use all() by performing the check for membership of a in b through an iterator on b:
a = [1,1,2]
b = [0, 1,1,1,2,1]
r = all(n in ib for ib in [iter(b)] for n in a)
print(r) # True
It will also find a match for items in the same relative order (that are not consecutive):
a=[1,2,1]
b=[1,2,3,1]
r = all(n in ib for ib in [iter(b)] for n in a)
print(r) # True
How it works:
every time n in ib is executed, the ib iterator advances up to the next matching value in b.
Going through all values of a will match items sequentially over the remainder of b after each match check
If ib is exhausted before getting to the end of a, then the elements aren't all present or their order doesn't match
If you are looking for consecutive matches, you can use the in operator on a generator that yields sublists of the corresponding length:
a = [1,1,2]
b = [0, 1,1,1,2,1]
r = a in (b[i:i+len(a)] for i in range(len(b)-len(a)+1))
print(r) # True

Count list occurence in list python

I'd like to count how many times a big list contains elements in specific order. So for example if i have elements [1,2,3,4,5,1,2,3,4,5,1,2,3,4,5,1,2,3,4,5] and i'd like to know how many times [1,2,3] are next to each other (answer is 4 in this case).
I was thinking on checking the indexes of number '3' (so currently it'd return [2,7,12,17]. Then i would iterate over that list, take elements in positions described in the list and check two positions in front of it. If they match '1' and '2' then add 1 to counter and keep looking. I believe this solution isn't really efficient and does not look nice, would there be a better solution?
Here's a generalized solution that works for subsequences of any size and for elements of any type. It's also very space-efficient, as it only operates on iterators.
from itertools import islice
def count(lst, seq):
it = zip(*(islice(lst, i, None) for i in range(len(seq))))
seq = tuple(seq)
return sum(x == seq for x in it)
In [4]: count(l, (1, 2, 3))
Out[4]: 4
The idea is to create a sliding window iterator of width len(seq) over lst, and count the number of tuples equal to tuple(seq). This means that count also counts overlapping matches:
In [5]: count('aaa', 'aa')
Out[5]: 2
For lists of ints, you could convert to strings and then use the count method:
>>> x = [1,2,3,4,5,1,2,3,4,5,1,2,3,4,5,1,2,3,4,5]
>>> y = [1,2,3]
>>> s = ',' + ','.join(str(i) for i in x) + ','
>>> t = ',' + ','.join(str(i) for i in y) + ','
>>> s.count(t)
4
If the items in the list contained strings which contain commas, this method could fail (as #schwobaseggl points out in the comments). You would need to pick a delimiter known not to occur in any of the strings, or adopt an entirely different approach which doesn't reduce to the string count method.
On Edit: I added a fix suggested by #Rawing to address a bug pointed out by #tobias_k . This turns out to be a more subtle problem than it first seems.
x = [1,2,3,4,5,1,2,3,4,5,1,2,3,4,5,1,2,3,4,5]
y = [1,2,3]
count = 0
for i in range(len(x)-len(y)):
if x[i:i+len(y)] == y:
count += 1
print(count)
You could iterate the list and compare sublists:
In [1]: lst = [1,2,3,4,5,1,2,3,4,5,1,2,3,4,5,1,2,3,4,5]
In [2]: sub = [1,2,3]
In [3]: [i for i, _ in enumerate(lst) if lst[i:i+len(sub)] == sub]
Out[3]: [0, 5, 10, 15]
Note, however, that on a very large list and sublist, this is pretty wasteful, as it creates very many slices of the original list to compare against the sublist. In a slightly longer version, you could use all to compare each of the relevant positions of the list with those of the sublist:
In [5]: [i for i, _ in enumerate(lst) if all(lst[i+k] == e for k, e in enumerate(sub))]
Out[5]: [0, 5, 10, 15]
This strikes me as the longest common subsequence problem repeated every time until the sequence returned is an empty list.
I think that the best that you can do in this case for an efficient algorithm is O(n*m) where n is the number of elements in your big list and m is the number of elements in your small list. You of course would have to have an extra step of removing the small sequence from the big sequence and repeating the process.
Here's the algorithm:
Find lcs(bigList, smallList)
Remove the first occurrence of the smallList from the bigList
Repeat until lcs is an empty list
Return the number of iterations
Here is an implementation of lcs that I wrote in python:
def lcs(first, second):
results = dict()
return lcs_mem(first, second, results)
def lcs_mem(first, second, results):
key = ""
if first > second:
key = first + "," + second
else:
key = second + "," + first
if len(first) == 0 or len(second) == 0:
return ''
elif key in results:
return results[key]
elif first[-1] == second[-1]:
result = lcs(first[:-1], second[:-1]) + first[-1]
results[key] = result
return result
else:
lcsLeft = lcs(first[:-1], second)
lcsRight = lcs(first, second[:-1])
if len(lcsLeft) > len(lcsRight):
return lcsLeft
else:
return lcsRight
def main():
pass
if __name__ == '__main__':
main()
Feel free to modify it to the above algorithm.
One can define the efficiency of solution from the complexity. Search more about complexity of algorithm in google.
And in your case, complexity is 2n where n is number of elements.
Here is the solution with the complexity n, cause it traverses the list only once, i.e. n number of times.
def IsSameError(x,y):
if (len(x) != len(y)):
return False
i = 0
while (i < len(y)):
if(x[i] != y[i]):
return False
i += 1
return True
x = [1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5]
y = [1, 2, 3]
xLength = len(x)
yLength = len(y)
cnt = 0
answer = []
while (cnt+3 < xLength):
if(IsSameError([x[cnt], x[cnt+1], x[cnt+2]], y)):
answer.append(x[cnt])
answer.append(x[cnt+1])
answer.append(x[cnt + 2])
cnt = cnt + 3
else:
cnt = cnt + 1
print answer

Counting number of list entries that occur 1 time

I'm trying to write a Python function that counts the number of entries in a list that occur exactly once.
For example, given the list [17], this function would return 1. Or given [3,3,-22,1,-22,1,3,0], it would return 1.
** Restriction: I cannot import anything into my program.
The incorrect code that I've written so far: I'm going the double-loop route, but the index math is getting over-complicated.
def count_unique(x):
if len(x) == 1:
return 1
i = 0
j = 1
for i in range(len(x)):
for j in range(j,len(x)):
if x[i] == x[j]:
del x[j]
j+1
j = 0
return len(x)
Since you can't use collections.Counter or sorted/itertools.groupby apparently (one of which would usually be my go to solution, depending on whether the inputs are hashable or sortable), just simulate roughly the same behavior as a Counter, counting all elements and then counting the number of elements that appeared only once at the end:
def count_unique(x):
if len(x) <= 1:
return len(x)
counts = {}
for val in x:
counts[val] = counts.get(val, 0) + 1
return sum(1 for count in counts.values() if count == 1)
lst = [3,3,-22,1,-22,1,3,0]
len(filter(lambda z : z[0] == 1,
map(lambda x : (len(filter(lambda y : y == x, lst)), x), lst)))
sorry :)
Your solution doesn't work because you are doing something weird. Deleting things from a list while iterating through it, j+1 makes no sense etc. Try adding elements that are found to be unique to a new list and then counting the number of things in it. Then figure out what my solution does.
Here is the O(n) solution btw:
lst = [3,3,-22,1,-22,1,3,0,37]
cnts = {}
for n in lst:
if n in cnts:
cnts[n] = cnts[n] + 1
else:
cnts[n] = 1
count = 0
for k, v in cnts.iteritems():
if v == 1:
count += 1
print count
A more simple and understandable solution:
l = [3, 3, -22, 1, -22, 1, 3, 0]
counter = 0
for el in l:
if l.count(el) == 1:
counter += 1
It's pretty simple. You iterate over the items of the list. Then you look if the element is exactly one time in the list and then you add +1. You can improve the code (make liste comprehensions, use lambda expressions and so on), but this is the idea behind it all and the most understandable, imo.
you are making this overly complicated. try using a dictionary where the key is the element in your list. that way if it exists it will be unique
to add to this. it is probably the best method when looking at complexity. an in lookup on a dictionary is considered O(1), the for loop is O(n) so total your time complexity is O(n) which is desirable... using count() on a list element does a search on the whole list for every element which is basically O(n^2)... thats bad
from collections import defaultdict
count_hash_table = defaultdict(int) # i am making a regular dictionary but its data type is an integer
elements = [3,3,-22,1,-22,1,3,0]
for element in elements:
count_hash_table[element] += 1 # here i am using that default datatype to count + 1 for each type
print sum(c for c in count_hash_table.values() if c == 1):
There is method on lists called count.... from this you can go further i guess.
for example:
for el in l:
if l.count(el) > 1:
continue
else:
print("found {0}".format(el))

Using recursion to create a list combination

I'm in trouble creating a combination of elements from list.
What i would like to do is to create a recursive function in Python which returns a combination of elements for example list a = [1,2,3,4,5,6,7,8] and a result will be combinations [1,2,3,4],[1,3,4,5],[1,4,5,6],[1,2,4,5] etc. For 8 elements it should return 70 combinations (if i did my math right). Although the best option would be that the combinations don't repeat.
I tried to code it, but what i get is only [1,2,3,4],[1,3,4,5] etc but not combination [1,5,7,8]
I know there is a special function but i'd like to do it recursively. Any suggestions?
nimed = ["A","B","C","D","E","F","G","H"]
def kombinatsioonid(listike,popitav):
if len(listike) < 4:
return
tyhi = []
for c in range(len(listike)):
tyhi.append(listike[c])
listike.pop(popitav)
print(tyhi)
kombinatsioonid(listike,popitav)
kombinatsioonid(nimed,1)
This can be done in this way :
def combination(l,n, mylist=[]):
if not n: print(mylist)
for i in range(len(l)):
mylist.append(l[i])
combination(l[i+1:], n-1, mylist)
mylist.pop()
l = ["A","B","C","D","E","F","G","H"]
n=4
combination(l, n)
For each element x in a, generate all k-1 combinations from the elements right to it, and prepend x to each one. If k==0, simply return one empty combination, thus exiting the recursion:
def combs(a, k):
if k == 0:
return [[]]
r = []
for i, x in enumerate(a):
for c in combs(a[i+1:], k - 1):
r.append([x] + c)
#print '\t' * k, k, 'of', a, '=', r
return r
Uncomment the "print" line to see what's going on.
As a side note, it's better to use English variable and function names, just for the sake of interoperability (your very question being an example).

List and Integer query

If i had a list of numbers and some maybe negative, how would i ensure all numbers in my list were positive? I can covert the items in the list to integers thats no problem.
Another question, I want to compare items in my list to an integer value say 'x' and sum all the values in my list that are less than x.
Thank you.
If you have a list Ns of numbers (if it's a list of strings as in several similar questions asked recently each will have to be made into an int, or whatever other kind of number, by calling int [[or float, etc]] on it), the list of their absolute values (if that's what you mean by "ensure") is
[abs(n) for n in Ns]
If you mean, instead, to check whether all numbers are >= 0, then
all(n >= 0 for n in Ns)
will give you a bool value respecting exactly that specification.
The sum of the items of the list that are <x is
sum(n for n in Ns if n < x)
Of course you may combine all these kinds of operations in one sweep (e.g. if you need to take the abs(n) as well as checking if it's < x, checking if it's >= 0, summing, whatever).
# input list is named "lst"
pos_list = [int(a) for a in lst if int(a) > 0]
# And num 2 (notice generator is used instead of list)
return sum(a for a in lst if a < x)
Answer / First part:
>>> a = [1, 2, -3, 4, 5, 6]
>>> b = [1, 2, 3, 4, 5, 6]
>>> max(map(lambda x: x < 0, a))
False
>>> max(map(lambda x: x < 0, b))
True
Or just use min:
>>> min(a) < 0
True
>>> min(b) < 0
False
Second part:
>>> x = 3
>>> sum(filter(lambda n: n < x, a))
>>> 0
>>> sum(filter(lambda n: n < x, b))
>>> 3
If I understand correctly your question, I guess you are asking because of some class about functional programming.
In this case, what you are asking for can be accomplished with functional programming tools available in Python.
In particular, the first point can be solved using filter, while the second with map and reduce (or, better, with map and sum).
>>>mylist = [1,2,3,-2]
>>>any(item for item in mylist if item < 0)
True
>>>mylist.pop()
-2
>>>any(item for item in mylist if item < 0)
False
answers your first question.
>>> x = 3
>>> sum(item for item in mylist if item < x)
3
answers your second question.

Categories

Resources