given an array print least frequent elements - python

You are given an array of numbers. Print the least occurring element. If there is more than 1 element print all of them in decreasing order of their value.
Input:
[9, 1, 6, 4, 56, 56, 56, 6, 4, 2]
Output:
[9, 2, 1]
I actually got output but doesn't execute private cases, please help me.
from collections import Counter
n=int(input())
ans=""
list1=[]
list2=[]
list1=[int(x) for x in input().strip().split()][:n]
dict1=dict(Counter(list1))
k=min(dict1,key=dict1.get)
l=dict1[k]
for i,j in dict1.items():
if(j==l):
list2.append(i)
list2.reverse()
for i in list2:
ans+=str(i)+' '
print(ans[:-1])

I see a lot of complicated answers. It can actually be done by just using list comprehension over the items in the instance of Counter():
>>> from collections import Counter
>>> count = Counter([9, 1, 6, 4, 56, 56, 56, 6, 4, 2])
>>> values = [key for key, value in count.items() if value == min(count.values())]
>>> values.sort(reverse=True) # [9, 2, 1]

The reason you are getting error is because Counter/Dictionary is an unordered collection. So your list2 could have elements in a different order each time you run it. Try running your code for [9, 1, 6, 4, 56, 6, 4, 2] input.
from collections import Counter
n=int(input())
list1=[]
list2=[]
list1=[int(x) for x in input().strip().split()][:n]
dict1=dict(Counter(list1))
k=min(dict1,key=dict1.get)
l=dict1[k]
for i,j in dict1.items():
if(j==l):
list2.append(i)
list2.sort(reverse=True)
print(' '.join(str(i) for i in list2))

Without any import you can also try
def getAllindex(lst, elem):
return list(filter(lambda a: lst[a] == elem, range(0,len(lst))))
lst = [9, 1, 6, 4, 56, 56, 56, 6, 4, 2]
list_count = [lst.count(xx) for xx in lst]
idx = getAllindex(list_count, min(list_count))
l = list(set([lst[ii] for ii in idx]))
l.sort(reverse = True)
print(l)
Output
[9, 2, 1]

You can do this by simply sorting the list before reversing it. and you need not create a string for list . simply *list_name and it will print list using spaces.
from collections import Counter
n=int(input())
list1=[]
list2=[]
list1=[int(x) for x in input().strip().split()][:n]
dict1=dict(Counter(list1))
k=min(dict1,key=dict1.get)
l=dict1[k]
for i,j in dict1.items():
if(j==l):
list2.append(i)
list2.sort(reverse=True)
print(*list2)

Related

how to find multiple non-repeating numbers in python?

I have a below method that finds the non-repeating elements in a list:
def dupes(a):
s = {}
for ele in a:
if ele not in s:
s[ele] = 1
else:
s[ele] += 1
for x in s:
if s[x] == 1:
return 'this is the only non-repeating element value is :', s[x], 'and the key is :', x
return
l = [4, 7, 4, 5, 7, 6, 5, 6, 10]
cd = dupes(l)
print("This is dupes: ", cd)
The code runs successfully and below is the output:
This is dupes: ('this is the only non-repeating element value is :', 1, 'and the key is :', 10)
But when I am trying to add more than one non-repeating elements in the list, the output doesn't change. For example, if I add 11 at the end of the list the output still remains the same as above..
Any idea?
Actually when you return at the 10th line, the function ends. This is in case you don't understand the list comprehension yet, as many have given you the solution with that technique. I will just give you a simple solution where it will return a list of non-repeating numbers.
def dupes(a):
s = {}
non_dupes = []
for ele in a:
if ele not in s:
s[ele] = 1
else:
s[ele] += 1
for x in s:
if s[x] == 1:
non_dupes.append(x)
return non_dupes
l = [4, 7, 4, 5, 7, 6, 5, 6, 10, 11]
cd = dupes(l)
print("This is dupes: ", cd)
def dupes(a):
s = {}
for ele in a:
if ele not in s:
s[ele] = 1
else:
s[ele] += 1
count = 0
keys = []
for x in s:
if s[x] == 1:
count += 1
keys.append(x)
return 'this is the only non-repeating element value is :', count, 'and the key is :', keys
That would be fine.
You can get all keys whose value is 1 using a list comprehension.
nondupes = [k for (k,v) in s.items() if v==1]
return 'Non-repeating elements: ' + str(nondupes)
Also, you could replace all your counting code with a collections.Counter:
s = Counter(a)
You can easely solve this in one line of python code, using the count() function:
l = [4, 7, 4, 5, 7, 6, 5, 6, 10 ,11]
only_one_time = [e for e in l if l.count(e) < 2]
print(only_one_time)
The given code returns the first non-repeating element it encounters.
For example,
if the input list is l = [12, 11, 4, 7, 4, 5, 7, 6, 5, 6, 10],
the output would be This is dupes: ('this is the only non-repeating element value is :', 1, 'and the key is :', 12).
You can succinctly achieve the above with Counter:
from collections import Counter
l = [4, 7, 4, 5, 7, 6, 5, 6, 10]
c = Counter(l)
dupes = list(key for key in c if c[key] > 1)
print("This is dupes: ", dupes)
Output:
This is dupes: [4, 7, 5, 6]
The issue that you are encountering is that you are returning prematurely from your function with a string containing the first duplicate. The rest of the duplicates are lost.
You already have the list of duplicates, let's return just the data so we can separate the calculation of results from the display of results.
return list(e for e in s if s[e] > 1)

Inserting a set of elements alternatively

There is a list with elements of similar nature (4 7's,3 5's, etc.) that I want to insert in right left order into a another list ().
newlst = []
lst = [7, 7, 7, 7, 5, 5, 5, 3, 3, 3, 2, 2]
So the first thing being inserted into newlst is the group of 7's:
newlst = [7,7,7,7]
Subsequently, the group of 5's is inserted into the list on the right:
newlst = [7, 7, 7, 7, 5, 5, 5]
And then the group of 3's is inserted on the left, and after that the group of 2's is inserted on the right. The final list looks like this
newlst = [3, 3, 3, 7, 7, 7, 7, 5, 5, 5, 2, 2]
In order to add elements in the list on a right left basis, I did this:
for i in lst:
lst.insert(0,i)
else:
lst.append(i)
The insert method inserts elements into the 0 index (which is the right of the list) and append adds elements at the end of the list (which is the left of the list). However, I'm having problems adding the group of elements into the newlst. To that end, I thought using a dictionary would be a good idea.
myDict = {2: 2, 3: 3, 5: 3, 7: 4}
EDIT:
for k, v in myDict.items():
if k in lst:
for i in range(v):
lst.append(i)
else:
lst.insert(0,i)
The intention of this dictionary is for each key, I want to insert the key value 'x' times, e.g. the key 7, would be inserted 4 times: [7,7,7,7]. Is there a way to achieve this in Python so I can get the output newlist: [3, 3, 3, 7, 7, 7, 7, 5, 5, 5, 2, 2] ?
You can accomplish this pretty easily with a deque, along with cycle and groupby
from collections import deque
from itertools import groupby, cycle
#creates a deque object
d = deque()
#creates a repeating iterator to alternate function calls
c = cycle([d.extendleft, d.extend])
lst = [7, 7, 7, 7, 5, 5, 5, 3, 3, 3, 2, 2]
for _, items in groupby(lst):
#calls the alternated function to extend the items
next(c)(items)
print(list(d))
>>> [3, 3, 3, 7, 7, 7, 7, 5, 5, 5, 2, 2]
Here is your initial code:
newlst = []
lst = [7, 7, 7, 7, 5, 5, 5, 3, 3, 3, 2, 2]
myDict = {2: 2, 3: 3, 5: 3, 7: 4}
for k, v in myDict.items():
if k in lst:
for i in range(v):
lst.append(i)
else:
lst.insert(0,i)
You have a few major problems here:
k is always in lst, by definition. That means your check is not a valid way to alternate.
Your data is getting appended/prepended to lst instead of newlst.
A dict is a hash-table. This means that the order of the keys will pretty much never be in the order you defined them in.
The first item can be solved through enumeration:
for i, (k, v) in enumerate(myDict.items()):
if i % 2:
newlst = [k] * v + newlst
else:
newlst += [k] * v
I've fixed the list you are appending to, and am using [k] * v to construct the prepended/appended list. newlst += [k] * v is equivalent to newlst.extend([k] * v). However, keep in mind that newlst = [k] * v + newlst creates a new list object rather than concatenating in-place.
The third item can be fixed using OrderedDict instead of a regular dict:
from collections import OrderedDict
...
myDict = OrderedDict([(2, 2), (3, 3), (5, 3), (7, 4)])
That will make the keys run in the order that you want. In fact, you don't need to construct myDict by hand at all. You can combine OrderedDict with a Counter to get the exact same result dynamically. The recipe for this is given in the OrderedDict docs:
from collections import Counter, OrderedDict
...
class OrderedCounter(Counter, OrderedDict):
def __repr__(self):
return '%s(%r)' % (self.__class__.__name__, OrderedDict(self))
def __reduce__(self):
return self.__class__, (OrderedDict(self),)
myDict = OrderedCounter(lst)
All this is pretty verbose and not very efficient. As #Wondercricket's answer points out, you can use the functions in itertools to perform the same task using generators.
This is what you want to do?
list = [7, 7, 7, 7, 5, 5, 5, 3, 3, 3, 2, 2]
def list_to_answerlist(list, default=[]):
if not list:
return default
else:
result = []
direction = True # Insert Direction: True = Insert Left / False = Insert Right
actual_group = list[0]
for element in list:
if (element != actual_group):
direction = not direction # Change Insert Direction
actual_group = element # Update Actual Group
if direction: # Insert Left
result.insert(0,element)
else: # Insert Right
result.append(element)
return result
new_list = list_to_answerlist(list) # output = [3, 3, 3, 7, 7, 7, 7, 5, 5, 5, 2, 2]

Python: split list into indices based on consecutive identical values

If you could advice me how to write the script to split list by number of values I mean:
my_list =[11,11,11,11,12,12,15,15,15,15,15,15,20,20,20]
And there are 11-4,12-2,15-6,20-3 items.
So in next list for exsample range(0:100)
I have to split on 4,2,6,3 parts
So I counted same values and function for split list, but it doen't work with list:
div=Counter(my_list).values() ##counts same values in the list
def chunk(it, size):
it = iter(it)
return iter(lambda: tuple(islice(it, size)), ())
What do I need:
Out: ([0,1,2,3],[4,5],[6,7,8,9,10,11], etc...]
You can use enumerate, itertools.groupby, and operator.itemgetter:
In [45]: import itertools
In [46]: import operator
In [47]: [[e[0] for e in d[1]] for d in itertools.groupby(enumerate(my_list), key=operator.itemgetter(1))]
Out[47]: [[0, 1, 2, 3], [4, 5], [6, 7, 8, 9, 10, 11], [12, 13, 14]]
What this does is as follows:
First it enumerates the items.
It groups them, using the second item in each enumeration tuple (the original value).
In the resulting list per group, it uses the first item in each tuple (the enumeration)
Solution in Python 3 , If you are only using counter :
from collections import Counter
my_list =[11,11,11,11,12,12,15,15,15,15,15,15,20,20,20]
count = Counter(my_list)
div= list(count.keys()) # take only keys
div.sort()
l = []
num = 0
for i in div:
t = []
for j in range(count[i]): # loop number of times it occurs in the list
t.append(num)
num+=1
l.append(t)
print(l)
Output:
[[0, 1, 2, 3], [4, 5], [6, 7, 8, 9, 10, 11], [12, 13, 14]]
Alternate Solution using set:
my_list =[11,11,11,11,12,12,15,15,15,15,15,15,20,20,20]
val = set(my_list) # filter only unique elements
ans = []
num = 0
for i in val:
temp = []
for j in range(my_list.count(i)): # loop till number of occurrence of each unique element
temp.append(num)
num+=1
ans.append(temp)
print(ans)
EDIT:
As per required changes made to get desired output as mention in comments by #Protoss Reed
my_list =[11,11,11,11,12,12,15,15,15,15,15,15,20,20,20]
val = list(set(my_list)) # filter only unique elements
val.sort() # because set is not sorted by default
ans = []
index = 0
l2 = [54,21,12,45,78,41,235,7,10,4,1,1,897,5,79]
for i in val:
temp = []
for j in range(my_list.count(i)): # loop till number of occurrence of each unique element
temp.append(l2[index])
index+=1
ans.append(temp)
print(ans)
Output:
[[54, 21, 12, 45], [78, 41], [235, 7, 10, 4, 1, 1], [897, 5, 79]]
Here I have to convert set into list because set is not sorted and I think remaining is self explanatory.
Another Solution if input is not always Sorted (using OrderedDict):
from collections import OrderedDict
v = OrderedDict({})
my_list=[12,12,11,11,11,11,20,20,20,15,15,15,15,15,15]
l2 = [54,21,12,45,78,41,235,7,10,4,1,1,897,5,79]
for i in my_list: # maintain count in dict
if i in v:
v[i]+=1
else:
v[i]=1
ans =[]
index = 0
for key,values in v.items():
temp = []
for j in range(values):
temp.append(l2[index])
index+=1
ans.append(temp)
print(ans)
Output:
[[54, 21], [12, 45, 78, 41], [235, 7, 10], [4, 1, 1, 897, 5, 79]]
Here I use OrderedDict to maintain order of input sequence which is random(unpredictable) in case of set.
Although I prefer #Ami Tavory's solution which is more pythonic.
[Extra work: If anybody can convert this solution into list comprehension it will be awesome because i tried but can not convert it to list comprehension and if you succeed please post it in comments it will help me to understand]

Appending a new value to python list

aList = []
for number in range (1,11):
aList += [number]
print ("printing",aList);
Output is:
printing
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
but if I modify like this (I expect 100 to be added to the end of the list)
aList = []
for number in range (1,11):
aList += [number]
aList += 100;
print ("printing",aList);
I get this error: TypeError: 'int' object is not iterable
You have three problems with your current code:
aList += 100 should be aList += [100]
You should remove all of the semicolons
aList += [100] should be moved to outside the for loop
For example:
In [2]:
aList = []
for number in range (1,11):
aList += [number]
aList += [100]
print ("printing",aList) # ('printing', [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 100])
You could also simply this to:
print ("printing", range(1, 11) + [100]) # ('printing', [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 100])
If you don't want to use .append() on a list:
aList = []
for number in range (1,11):
aList += [number]
aList += [100]
print ("printing",aList)
Please note that you don't need the semicolon at the end of the line (;)
range returns a list, hence this much is sufficient instead of for loop
aList = range(1, 11)
to add '100' as last element, add one more statement
aList += [100]
or
aList.append(100)
range is a list. Hence, you can just do:
aList = range(10) + [100]

Finding repeated values in multiple lists

I am trying to find if any of the sublists in list1 has a repeated value, so i need to be told if a number in list1[0] is the same number in list[1] (which 20 is repeated)
the numbers represent coords and the coords of each item in list1 cannot over lap, if they do then i have a module that reruns a make a new list1 untill no coords are the smae
please help
list1 = [[7, 20], [20, 31, 32], [66, 67, 68],[7, 8, 9, 2],
[83, 84, 20, 86, 87], [144, 145, 146, 147, 148, 149]]
x=0
while x != 169:
if list1.count(x) > 0:
print ("repeat found")
else:
print ("no repeat found")
x+=1
How about something like:
is_dup = sum(1 for l in list1 if len(set(l)) < len(l))
if is_dup > 0:
print ("repeat found")
else:
print ("no repeat found")
Another example using any:
any(len(set(l)) < len(l) for l in list1)
To check if only one item is repeated in all of the lists I would chain them and check. Credit to this answer for flattening a list of lists.
flattened = sum(list1, [])
if len(flattened) > len(set(flattened)):
print ("dups")
else:
print ("no dups")
I guess the proper way to flatten lists is to use itertools.chain which can be used as such:
flattened = list(itertools.chain(*list1))
This can replace the sum call I used above if that seems like a hack.
Solution for the updated question
def has_duplicates(iterable):
"""Searching for duplicates in sub iterables.
This approach can be faster than whole-container solutions
with flattening if duplicates in large iterables are found
early.
"""
seen = set()
for sub_list in iterable:
for item in sub_list:
if item in seen:
return True
seen.add(item)
return False
>>> has_duplicates(list1)
True
>>> has_duplicates([[1, 2], [4, 5]])
False
>>> has_duplicates([[1, 2], [4, 5, 1]])
True
Lookup in a set is fast. Don't use a list for seen if you want it to be fast.
Solution for the original version of the question
If the length of the list is larger than the length of the set made form this list there must be repeated items because a set can only have unique elements:
>>> L = [[1, 1, 2], [1, 2, 3], [4, 4, 4]]
>>> [len(item) - len(set(item)) for item in L]
[1, 0, 2]
This is the key here
>>> {1, 2, 3, 1, 2, 1}
set([1, 2, 3])
EDIT
If your are not interested in the number of repeats for each sub list. This would be more efficient because its stops after the first number greater than 0:
>>> any(len(item) - len(set(item)) for item in L)
True
Thanks to #mata for pointing this out.
from collections import Counter
list1=[[7, 20], [20, 31, 32], [66, 67, 68],
[7, 8, 9, 2], [83, 84, 20, 86, 87],
[144,144, 145, 146, 147, 148, 149]]
for i,l in enumerate(list1):
for r in [x for x,y in Counter(x for x in l).items() if y > 1]:
print 'at list ', i, ' item ', r , ' repeats'
and this one gives globally repeated values:
expl=sorted([x for l in list1 for x in l])
print [x for x,y in zip(expl, expl[1:]) if x==y]
For Python 2.7+, you should try a Counter:
import collections
list = [1, 2, 3, 2, 1]
count = collections.Counter(list)
Then count would be like:
Counter({1: 2, 2: 2, 3:1})
Read more

Categories

Resources