Couting unique elements in python - python

I need a program which is couting unique elements in a list, but WITHOUT any built-in functions. I'm only allowed to use different lists and index of elements.
So if theres a list: [1, 6, 7, 2, 1, 6], solution must be: 4.

Starting with a second, empty list, use for to iterate over the items in your input list, check if they're in the new list, and if not then add them. Each time you do so, increment a counter by 1.

list1 = [1, 6, 7, 2, 1, 6]
list2 = []
Simple solution using set:
print len(set(list1))
Solution using list:
for i in list1:
if i not in list2:
list2.append(i)
print len(list2)
without len function:
for i in list1:
if i not in list2:
list2.append(i)
count = 0
for i in list2:
count += 1
print count

Related

Ideas for the following function?

I would like to develop a function which would always based on the first element in the list extract further elements of the nested list.
Example:
Input:
lst= [[1,2,3],[3,4,5,6,8,9], [0,3,4], [1,4,5,6], [4,9,8,6,5,2]]
The first element in the sublist always determines the number of following elements to append to a new list.
Output:
Out=[2,4,5,6,4,9,8,6,5]
Elements are always an integer values.
Maybe this is what you expect:
Or you can convert this to List Comprehension later.
out = []
for sub in lst: # loop each sublist
start = sub[0] # use the first num. to determine
out.extend(sub[1: 1+start]) # get each sublist by slicing
print(out)
[2, 4, 5, 6, 4, 9, 8, 6, 5]

Find count of number of pairs in the list

I have list of numbers:
[5, 4, 3, 4, 2, 1, 3, 5, 3, 5, 3, 5,]
A pair of numbers is the same 2 numbers. For example, 5 occurs 4 times, so we have 2 pairs of 5s. In the list above I can say I have 5 pairs. I want the output to count how many pairs of numbers are in the list.
I tried this, but got stuck.
list = [5,4,3,4,2,1,3,5]
print(list)
temp = 0
new_list = []
for index,x in enumerate(list):
elm_count = list.count(list[index])
if new_list:
for ind, y in enumerate(new_list):
if list[index] == new_list[ind]:
continue
if not elm_count % 2:
occ_count = elm_count/2
temp += occ_count
new_list.append(list[index])
continue
Simpler way to achieve this is using collections.Counter() with sum() as:
>>> my_list = [5, 4, 3, 4, 2, 1, 3, 5,3, 5, 3, 5,]
>>> sum(num//2 for num in Counter(my_list).values())
5
Here Counter() will generate a dict with number as key and count of occurrence of number in list as its value. Then I am iterating over its values and calculating the count of pairs for each number using generator expression, and doing summation on the count of all the pairs using sum().
You can refer below documents for more details:
collections.Counter() document
sum() document
To add, a solution without importing a package:
# Accepts a list of numbers as argument
def get_pairs(l):
already_counted = []
list_of_pairs = []
for i in l:
if not i in already_counted:
already_counted.append(i)
list_of_pairs.append(ar.count(i)//2)
return sum(list_of_pairs)
get_pairs([4,3,3,4,2,3,2,1,5]) # Run

Python: How to merge two lists like a zip with for loop

I am given a problem where I have a function that takes two integer lists and returns a single integer list (new list) with the two integer lists zipped together.
For example:
list1 = [1,2,3]
list2 = [4,5,6]
Should give [1, 4, 2, 5, 3, 6] not [1, 2, 3, 4, 5, 6]
Another case is if one list is longer than another, e.g:
list1 = [1,2]
list2 = [4,5,6,9]
Once the shorter list runs out of items, the longer list should add its remaining elements. E.g: [1, 4, 2, 5, 6, 9]
I have tried using conditional statements to check which list is longer and use a for loop to append to a new list that should be returned. I tried using for loops that loop for the duration of the shorter list, and once the for loop is over, it adds the remaining elements from longer list to the new list. Also if both lists are empty I have to return an empty new list.
The code:
def main():
list1 = [1,2]
list2 = [4,5,6,9]
print(zip_lists(list1, list2))
def zip_lists(list1, list2):
new_list = []
if len(list1) > len(list2):
last_num = list1[len(list1):]
for num in range(0, len(list2)):
new_list.append(list1[num])
new_list.append(list2[num])
new_list.append(last_num)
return new_list
elif len(list2) > len(list1):
last_num = list2[len(list2):]
for num in range(0, len(list1)):
new_list.append(list1[num])
new_list.append(list2[num])
new_list.append(last_num)
return new_list
elif len(list1) and len(list2) == 0:
return new_list
main()
However, I have a problem where I cannot add the remaining elements from the longer list and instead returns a partially zipped list with empty square brackets.
The test case:
list1 = [1,2]
list2 = [4,5,6,9]
Should be [1, 4, 2, 5, 6, 9] but I'm getting [1, 4, 2, 5, []].
Is my code showing the right way of thinking about this problem?
def zip_lists(list1, list2):
n1=len(list1)
n2=len(list2)
k = []
n = min(n1, n2)
for i in range(n):
k.append(list1[i])
k.append(list2[i])
if n1==n2:
return k
if n1>n2:
return k+list1[n:]
else:
return k+list2[n:]
Test:
list1 = [1,2]
list2 = [4,5,6,9]
zip_lists(list1, list2)
Output: [1, 4, 2, 5, 6, 9]
You can use zip_longest to do that like:
Code:
from itertools import zip_longest
def merge(l1, l2):
for i in zip_longest(l1, l2):
for j in i:
if j is not None:
yield j
Test Code:
list1 = [1, 2, 3]
list2 = [4, 5, 6]
ans1 = [1, 4, 2, 5, 3, 6]
list3 = [1, 2]
list4 = [4, 5, 6, 9]
ans2 = [1, 4, 2, 5, 6, 9]
assert list(merge(list1, list2)) == ans1
assert list(merge(list3, list4)) == ans2
A general version of this (i.e., for any number of source iterables, of possibly different lengths) is shown in the Python documentation for the itertools standard library, named roundrobin in the "recipes" section. Copied here, with the original credit:
def roundrobin(*iterables):
"roundrobin('ABC', 'D', 'EF') --> A D E B F C"
# Recipe credited to George Sakkis
num_active = len(iterables)
nexts = cycle(iter(it).__next__ for it in iterables)
while num_active:
try:
for next in nexts:
yield next()
except StopIteration:
# Remove the iterator we just exhausted from the cycle.
num_active -= 1
nexts = cycle(islice(nexts, num_active))
Here, cycle and islice are the functions provided by itertools (from itertools import cycle, islice); the rest is built-in. Note that this is a generator, not a normal function; you will need to iterate over it yourself (or directly create e.g. a list from it, e.g. merged = list(roundrobin(list1, list2))).
As far as debugging your attempt at the code, let's consider the case where list1 is longer (the case where list2 is longer has parallel problems; and the case where they're equal is working fine, yes?):
last_num = list1[len(list1):] # problem 1
for num in range(0, len(list2)):
new_list.append(list1[num])
new_list.append(list2[num])
new_list.append(last_num) # problem 2
Problem 1: you want to extract the "excess" elements from list1, which you determine as all the ones past a certain point. This is just a typo or not thinking about it clearly; you want to use the length of list2 for the number of elements to slice off; of course, using the length of list1 to remove elements from list1 removes everything.
Problem 2: you have a list whose elements you want to concatenate to the end of another list. .append treats its parameter as a single new list element, even if it's a list; like the Zen of Python says, special cases aren't special enough to break the rules (keep in mind that sometimes you might want to do this, after all). The method you're looking for, instead, is .extend.
import numpy as np
l=len(a) if len(a)<len(b) else len(b)
a=np.array(list1[:l])
b=np.array(list2[:l])
ab=np.vstack((a, b)).T.flatten()
res=list(ab)+list1[l:]+list2[l:]

List Duplicate Removal Issue?

I wrote a code that eliminates duplicates from a list in Python. Here it is:
List = [4, 2, 3, 1, 7, 4, 5, 6, 5]
NewList = []
for i in List:
if List[i] not in NewList:
NewList.append(i)
print ("Original List:", List)
print ("Reworked List:", NewList)
However the output is:
Original List: [4, 2, 3, 1, 7, 4, 5, 6, 5]
Reworked List: [4, 2, 3, 7, 6]
Why is the 1 missing from the output?
Using set() kills the order. You can try this :
>>> from collections import OrderedDict
>>> NewList = list(OrderedDict.fromkeys(List))
You missunderstood how for loops in python work. If you write for i in List: i will have the values from the list one after another, so in your case 4, 2, 3 ...
I assume you thought it'd be counting up.
You have several different ways of removing duplicates from lists in python that you don't need to write yourself, like converting it to a set and back to a list.
list(set(List))
Also you should read Pep8 and name your variables differently, but that just btw.
Also if you really want a loop with indices, you can use enumerate in python.
for idx, value in enumerate(myList):
print(idx)
print(myList[idx])
Your code is not doing what you think it does. Your problem are these two constructs:
for i in List: # 1
if List[i] # 2
Here you are using i to represent the elements inside the list: 4, 2, 3, ...
Here you are using i to represent the indices of the List: 0, 1, 2, ...
Obviously, 1. and 2. are not compatible. In short, your check is performed for a different element than the one you put in your list.
You can fix this by treating i consistently at both steps:
for i in List:
if i not in NewList:
NewList.append(i)
Your method for iterating over lists is not correct. Your code currently iterates over elements, but then does not use that element in your logic. Your code doesn't error because the values of your list happen also to be valid list indices.
You have a few options:
#1 Iterate over elements directly
Use elements of a list as you iterate over them directly:
NewList = []
for el in L:
if el not in NewList:
NewList.append(i)
#2 Iterate over list index
This is often considered anti-pattern, but is not invalid. You can iterate over the range of the size of the list and then use list indexing:
NewList = []
for idx in range(len(L)):
if L[idx] not in NewList:
NewList.append(i)
In both cases, notice how we avoid naming variables after built-ins. Don't use list or List, you can use L instead.
#3 unique_everseen
It's more efficient to implement hashing for O(1) lookup complexity. There is a unique_everseen recipe in the itertools docs, replicated in 3rd party toolz.unique. This works by using a seen set and tracking items as you iterate.
from toolz import unique
NewList = list(unique(L))

To find out whether a list is a sublist of a list

list1=[1,3,8,10,23,8,8,10,23,3,8,10,23,3,8,10,23]
list2=[10,23,3]
cnt=list1.count(list2[0])
cnt1=1
j=0
while (cnt1<=cnt):
list3=[]
list3.append(list2[0])
i=1
k=list1.index(list2[0])
while (i<len(list2)):
list3.append(list1[k+i])
i=i+1
print (list3)
if (list2==list3):
print ("list2 is a subset")
j=j+1
else:
print ("list2 is not a subset")
list1.remove(list2[0])
cnt1=cnt1+1
print (list2,"occurs",j,"times")
I am getting this error.
Traceback (most recent call last):
File "C:\Python26\Lib\idlelib\sublist.py", line 12, in <module>
list3.append(list1[k+i])
IndexError: list index out of range"
You're definitely over-complicating this - to the point where it is not obvious as to what your strategy actually is.
Here's a simple algorithm you could try and integrate:
Get the length of list2
Iterate through list1, accessing slices of the list of length list2 (eg the first slice would be [1, 3, 8], then the next would be [3, 8, 10]
Check if the slice is equal to list2 - if it is then return True (or add 1 to the counter)
If you reach the end of the list - end
You can test all the list1 slices of the proper length for equality with list2. You can then use sum to get the number of occurrences:
list1 = [1,3,8,10,23,8,8,10,23,3,8,10,23,3,8,10,23]
list2 = [10,23,3]
l1, l2 = len(list1), len(list2)
num_occurrences = sum(list1[i:i+l2] == list2 for i in range(l1 - l2 + 1))
# 2
Here is one possible way to do it:
from collections import deque
from itertools import islice
list1=[1,3,8,10,23,8,8,10,23,3,8,10,23,3,8,10,23]
list2=[10,23,3]
size = len(list2)
# convert to a queue
items = deque(list1)
count = 0
# iterate until no more sublists can be extracted
while len(items) >= size:
current = list(islice(items, 0, size))
# if the current sublist is equal to list1, increment count
if current == list2:
count += 1
# pop the first element from this queue, ready for next sublist
items.popleft()
print (list2,"occurs",count,"times")
Which Outputs:
[10, 23, 3] occurs 2 times
The approach of the above code:
Convert list1 to a collections.deque object, which can pop objects off the front in O(1) time. This is items in the code.
Store a count of identical lists found equal to list2.
Check if the current sub list, the first n elements in items as a list, is equal to list2. Increment the count if it is equal.
Pop the first item from items with popleft(), getting ready for the next sub list. So if my list is [1, 2, 3, 4], After processing [1, 2, 3], pop 1 from items, and the next sub list to check is [2, 3, 4].
Keep doing this process until no size sub lists can be extracted. Then you can just print out the count at the end.

Categories

Resources