With a list of numbers, each number can appear multiple times, i need to find the least common number in the list. If different numbers have the same lowest frequency, the result is the one occurring last in the list. An example, the least common integer in [1, 7, 2, 1, 2] is 7 (not 2, as originally said). And the list needs to stay unsorted
I have the following but it always sets the last entry to leastCommon
def least_common_in_unsorted(integers):
leastCommon = integers[0]
check = 1
appears = 1
for currentPosition in integers:
if currentPosition == leastCommon:
appears + 1
elif currentPosition != leastCommon:
if check <= appears:
check = 1
appears = 1
leastCommon = currentPosition
return leastCommon
Any help would be greatly appreciated
It is the simplest way come in my mind right now:
a = [1, 7, 2, 1, 2]
c, least = len(a), 0
for x in a:
if a.count(x) <= c :
c = a.count(x)
least = x
least # 7
and in two least items it will return the last occurrence one.
a = [1, 7, 2, 1, 2, 7] # least = 7
Using the Counter:
from collections import Counter
lst = [1, 7, 2, 1, 2]
cnt = Counter(lst)
mincnt = min(cnt.values())
minval = next(n for n in reversed(lst) if cnt[n] == mincnt)
print(minval) #7
This answer is based on #offtoffel to incorporate multiple items of the same number of occurrences while choosing the last occurring one:
def least_common(lst):
return min(lst, key=lambda x: (lst.count(x), lst[::-1].index(x)))
print(least_common([1,2,1,2]))
# 2
print(least_common([1,2,7,1,2]))
# 7
Edit: I noticed that there’s a even simpler solution, that is efficient and effective (just reverse the list in the beginning and min will keep the last value that has the minimum count):
def least_common(lst):
lst = lst[::-1]
return min(lst, key=lst.count)
print(least_common([1,2,1,2]))
# 2
print(least_common([1,2,7,1,2]))
# 7
Short but inefficient:
>>> min(a[::-1], key=a.count)
7
Efficient version using collections.Counter:
>>> min(a[::-1], key=Counter(a).get)
7
def least_common(lst):
return min(set(lst), key=lst.count)
Edit: sorry, this does not always take the last list item with least occurancy, as demanded by the user...it works on the example, but not for every instance.
Related
I'm working on an exercise where I have to find the unique number of a list the fastest way. The list will have at least 3 numbers and will be composed by only 2 different numbers not more and it has to be fast enough to avoid the times out.
Moreover, I have to return the result as a number not as a list, I tried to use
''.join(map(str, my_list)) but the test aren't good on it because it convert the value of the list as a string.
I've made this code:
def find_uniq(arr):
my_list = []
prev = ""
for i in range(len(arr)):
prev = arr[0]
if prev != arr[i]:
return arr[i]
When I executed the test on it, every test worked perfectly but there's one that crashed every time. It's the case when the unique number is in arr[0].
I know there is code on stackoverflow for this exercise, but I would like to solve it without looking at an explicit solution.
I don't know what condition to add to avoid this problem please.
I passed the test in those case:
find_uniq([ 1, 1, 1, 2, 1, 1 ])
find_uniq([ 0, 0, 0.55, 0, 0 ])
find_uniq([ 3, 10, 3, 3, 3 ])
But for example, I fail this one:
find_uniq([ 10, 3, 3, 3, 3 ])
I got 3 in return value.
As stated in the question: ...The list will have at least 3 numbers and will be composed by only 2 different numbers...:
l = [10,3,3,3]
for v1, v2, v3 in zip(l, l[1:], l[2:]):
if v1 == v2 == v3:
continue
elif v1 != v2 == v3:
print(v1)
break
elif v1 != v2 != v3:
print(v2)
break
elif v1 == v2 != v3:
print(v3)
break
Will print:
10
You are supposed that unique number is not first element of list. By comparing other element by first element of list you are limited to this and your code does not work on
find_uniq([ 10, 3, 3, 3, 3 ])
For have a complete solution, as you have at least 3 elements in list,
def find_uniq(arr):
count_first=0
count_second=0
first=arr[0]
second=nan
i=1
while(i<len(arr)):
if(arr[i]!=first):
second=arr[i]
count_second+=1
if(count_second>1):
return first;
else:
count_first+=1
if(count_first>1):
return second;
i+=1
def find_uniq(arr):
my_list = []
for i in range(len(arr)):
if arr.count(arr[i])==1:
my_list.append(arr[i])
return my_list
Try this hopefully this will work as you want this function return list of number that are unique in given list
Use collections.Counter:
from collections import Counter
def find_unique(arr):
return Counter(arr).most_common()[-1][0]
most_common will return a list of two 2-tuples, each consisting of an element and the number of times it appears. The unique element will, by definition, be the least common element and appear at the end of the list.
For example, Counter([ 0, 0, 0.55, 0, 0 ]).most_common() returns [(0, 4), (0.55, 1)].
Try this one:
def find_uniq(arr):
return [el for el in set(arr) if arr.count(el)==1]
I have a list, and I want to sum all the numbers in that list ...
except that if a 6 comes up - that is not counted and any number from that 6, until a next 7 comes up (also not counting the 7). A 7 always will appear somewhere after a 6.
For example:
my_list = [1,2,3,6,1,1,1,7,2,2,2]
1,2,3,.........,2,2,2 # Omit numbers from the first 6 to the next 7.
should output 12.
I know how to identify the 6, I'm just not sure how to not count the numbers until a followup 7 comes.
Thank you.
You can use a boolean as a flag. This should do it:
list= [1,2,3,6,1,1,1,7,2,2,2]
do_sum = True
total_sum = 0
for item in list:
if item == 6:
do_sum = False
if do_sum:
total_sum += item
if not do_sum and item == 7:
do_sum = True
The last if will check if the 6 went before the 7. So it will sum any seven that appears before a 6.
This solution supports multiple cases of sixes and sevens pairs in the list.
Let's do this as we would on paper:
Find the first 6; mark the list up to that point.
In the rest of the list, find the first 7; mark the list after that point.
Combine the two marked list portions; sum those elements.
Code, with a line of tracing output:
seq = [1, 2, 3, 6, 1, 1, 1, 7, 2, 2, 2]
first6 = seq.index(6)
rest = seq[first6:]
next7 = rest.index(7)
sum_list = seq[:first6] + rest[next7+1:]
print("Add these:", sum_list)
print("Sum:", sum(sum_list))
Output:
Add these: [1, 2, 3, 2, 2, 2]
Sum: 12
You can shorten the code by combining expressions, but I think this is more readable for you at this stage of your programming career.
I am new to coding and i spent over an hour looking for this with no luck.
So i have a def function which takes as an input a lst and a position.
I need python to correspond the inputed position to the lst and use whatever value is reflected on that position of the lst to calculate further.
def somefunction(lst, position):
for i, value in enumerate(lst):
if value < int(position): #this just uses the inputed value position and not the actual position value from the list
count += 1
return count
>>> somefunction([21, 4, 5, 66, 4, 3, 555], 2)
2
so at position 2 we have 5 and i need my code to return a count of all numbers smaller than 5 to the right of it only. so the answer would be 2...... since 4 and 3 are smaller than 5.
def somefunction(my_list, index):
value, tail = my_list[index], my_list[index + 1:]
return sum(1 for element in tail if element < value)
The "tail" of a list after the position n is lst[n+1:] in python:
>>> lst = [21, 4, 5, 66, 4, 3, 555]
>>> n = 2
>>> tail = lst[n+1:]
>>> tail
[66, 4, 3, 555]
To pick all elements that meet a certain condition you use a "list comprehension":
>>> smaller = [x for x in tail if x < lst[n]]
>>> smaller
[4, 3]
Finally, to count items in a list, use len:
>>> count = len(smaller)
>>> count
2
Hope this helps.
def somefunction(lst, position):
count=0
for i in range(position,len(lst)):
if lst[i] < lst[position]:
count += 1
return count
somefunction([21, 4, 5, 66, 4, 3,555], 2)
There are lots of ways to do it. as said by above people. since you have asked something similar to your code , i hope this helps you out. but as a beginner you could explore all options also
I have a time series representing regular queries into the functionality of a system, where 1 = working and 0 = not working. For example, expressing the time series as a list
U = [0,0,1,1,1,1,1,1,0,0,0,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,0]
I am interested in calculating things like the mean time to failure (how long the system stays up) and the mean time to repair (how long the system stays down) and other similar statistics so what I want to do is count the sequential 1 entries and the sequential 0 entries. I want to trim off the beginning and end sets since, for the example above, I don't know when the system went down initially nor when it will come back up in the future. So the output I'd be looking to generate in this case would be
uptime = [6, 4, 9, 2] # 6 ones followed by zeros, then 4 ones followed by zeros, etc.
downtime = [3, 3, 2] # like uptime but ignoring zeros at indices [0,1] and [-1]
I've written a script that does this but it seems a little bit awkward and I'm wondering if there's a better, more pythonic way to do it. Here's what I have.
def count_times(U, down=False):
if down:
U = [1 - u for u in U]
T = []
# Skip the first entry as you don't know when it started
m = U.index(0)
m += U[m:].index(1)
while m < len(U):
try:
T.append(U[m:].index(0))
m += U[m:].index(0)
m += U[m:].index(1)
except ValueError:
# skip the last entry as you don't know when it will end
return T
yielding:
print count_times(U)
# [6, 4, 9, 2]
print count_times(U, down = True)
# [3, 3, 2]
This works, but I can't help but wonder if there is a cleaner way to do this?
My approach is similar to Ruben's, but it initially keeps the up and down times in the same list after applying groupby, so it's easier to trim the beginning and ending sets.
import itertools
U = [0,0,1,1,1,1,1,1,0,0,0,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,0]
run_lengths = [(value, len(list(group))) for value, group in itertools.groupby(U)]
#discard first and last runs
run_lengths = run_lengths[1:-1]
#split runs into separate up and down time lists
uptime = [length for value, length in run_lengths if value == 1]
downtime = [length for value, length in run_lengths if value == 0]
print uptime
print downtime
Result:
[6, 4, 9, 2]
[3, 3, 2]
You can use groupby from itertools module:
from itertools import groupby
testvalue = [0,0,1,1,1,1,1,1,0,0,0,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,0]
def count_times(U, down=False):
if down:
return [len(list(group)) for key, group in groupby(U) if key == 0]
else:
return [len(list(group)) for key, group in groupby(U) if key == 1]
print count_times(testvalues, True) # [2, 3, 3, 2, 1]
print count_times(testvalues, False) # [6, 4, 9, 2]
Using reduce.
def groups(U,i):
a = reduce(lambda u,v: (u[0],u[1]+1) if v==i else (u[0] + [u[1]], 0) if u[1]>0 else u, U,([],0))[0]
if U[0]== i: a=a[1:] # truncate begining
if U[-1]==i: a=a[:-1] # truncate end
return a
U = [0,0,1,1,1,1,1,1,0,0,0,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,0]
uptime = groups(U,1)
downtime = groups(U,0)
This is sometimes called run-length encoding. R has a nice built-in function for this rle(). Anyway here is my approach, originally thought about using takewhile() but this is the cleanest way I could think of:
from itertools import chain
def rle(x):
x = chain(x)
last = x.next()
i = 1
for item in x:
if item != last:
yield (last, i)
i = 1
else:
i += 1
last = item
yield (last, i)
Then you can get downtime or uptime like so:
[L for v,L in rle(U) if v == 1]
[L for v,L in rle(U) if v == 0]
I want to shuffle the elements of a list without importing any module.
The type of shuffle is a riffle shuffle. It is where you want to divide the number of elements of the list into two and then interleave them.
If there are odd number of elements then the second half should contain the extra element.
eg:
list = [1,2,3,4,5,6,7]
Then the final list should look like
[1,4,2,5,3,6,7]
Just for fun, a recursive solution:
def interleave(lst1, lst2):
if not lst1:
return lst2
elif not lst2:
return lst1
return lst1[0:1] + interleave(lst2, lst1[1:])
Use it as follows in Python 2.x (In Python 3.x, use // instead of /):
lst = [1,2,3,4,5,6,7]
interleave(lst[:len(lst)/2], lst[len(lst)/2:])
=> [1, 4, 2, 5, 3, 6, 7]
The above will work fine with lists of any length, it doesn't matter if the length is even or odd.
listA = [1,2,3,4,5,6,7,8,9]
listLen = len(listA)/2
listB = listA[:listLen]
listC = listA[listLen:]
listD = []
num = 0
while num < listLen:
if len(listB) >= num:
listD.append(listB[num])
listD.append(listC[num])
num += 1
if len(listA)%2 != 0:
listD.append(listC[num])
print listD
After looking at another answer, I also am adding a recursive version, which is a revised version of the other guy's answer, but easier to call as you only have to call the function with a single argument (The list you are trying to have shuffled) and it does everything else:
def interleave(lst):
def interleaveHelper(lst1,lst2):
if not lst1:
return lst2
elif not lst2:
return lst1
return lst1[0:1] + interleaveHelper(lst2, lst1[1:])
return interleaveHelper(lst[:len(lst)/2], lst[len(lst)/2:])
When you go to call it, you can say interleave(list)
eg: list = [1,2,3,4,5,6,7]
then the final list should look like [1,4,2,5,3,6,7]
Here's a function that should do this reliably:
def riffle(deck):
'''
Shuffle a list like a deck of cards.
i.e. given a list, split with second set have the extra if len is odd
and then interleave, second deck's first item after first deck's first item
and so on. Thus:
riffle([1,2,3,4,5,6,7])
returns [1, 4, 2, 5, 3, 6, 7]
'''
cut = len(deck) // 2 # floor division
deck, second_deck = deck[:cut], deck[cut:]
for index, item in enumerate(second_deck):
insert_index = index*2 + 1
deck.insert(insert_index, item)
return deck
and to unit-test it...
import unittest
class RiffleTestCase(unittest.TestCase):
def test_riffle(self):
self.assertEqual(riffle(['a','b','c','d','e']), ['a','c','b','d','e'])
self.assertEqual(riffle([1,2,3,4,5,6,7]), [1,4,2,5,3,6,7])
unittest.main()
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
You could do this fairly easily with by utilizing the next feature of an iterator in Python.
First thing you'll want to do is split the elements into two parts.
Next, turn those two parts into iterators using Python's iter function. You could skip this step, but I find calling next(iterable) to be a lot cleaner than manually indexing a list.
Finally, you'll loop through the first half of your list, and for each element you add of that half, add the corresponding element of the latter (calling next gives the next item in the sequence).
For example:
elements = [1,2,3,4,5,6,7]
half_point = len(elements)/2
a = iter(elements[0:half_point])
b = iter(elements[half_point: ])
result = []
for i in range(half_point):
result.append(next(a))
result.append(next(b))
if len(elements) % 2 != 0:
result.append(next(b))
print result
>>> [1, 4, 2, 5, 3, 6, 7]
The last bit at the bottom checks to see if the list is odd. If it is, that it appends the final element onto the end of the list.
If you get creative, you could probably condense this down a good bit by zipping and then unpacking, but I'll leave that for when you explore itertools ;)
You can split the input list into two parts, then use zip and some list manipulation to interleave the items.
n = 9
l = range(1,n+1)
a = l[:n/2]
b = l[n/2:]
c = zip(a,b)
d = list()
for p in c :
d.extend(list(p))
if n%2==1:
d.append(b[n/2])
print(d)
def riffle(deck):
new_deck = []
deck_1 = deck[:len(deck)//2]
deck_2 = deck[len(deck)//2::]
for i in range(len(deck)//2):
new_deck.append(deck_1[i])
new_deck.append(deck_2[i])
if len(deck) % 2 == 1:
new_deck.append(deck[-1])
return new_deck
deck = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
print(riffle(deck))
You may find the expression i%2, which evaluates to 0 on even numbers and 1 on odd numbers, to alternatively access the beginning and middle of the deck.
def riffle(deck: List[int]) -> List[int]:
result = []
mid = len(deck) // 2
for i in range(len(deck)):
result.append(deck[i // 2 + (i % 2) * mid])
return result
Or you can utilize an if expression for the odd and even numbers respectively:
def riffle(deck: List[int]) -> List[int]:
result = []
mid = len(deck) // 2
for i in range(len(deck)):
if not i % 2:
result.append(deck[i // 2])
else:
result.append(deck[i // 2 + mid])
return result
>>> ll = list(range(1,8))
>>> mid = len(ll)/2 # for Python3, use '//' operator
>>> it1 = iter(ll[:mid])
>>> it2 = iter(ll[mid:])
>>> riff = sum(zip(it1,it2), ()) + tuple(it2)
>>> riff
(1, 4, 2, 5, 3, 6, 7)
If this is homework, be prepared to explain how sum and zip working here, what the second parameter to sum is for, why tuple(it2) is being added to the end, and how this solution has an inherent inefficiency.
If deck is a list, write a function that does list comprehension to perform the shuffling:
def riffle_shuffle(deck):
return [deck[i//2 + (i%2)*(len(deck)//2)] for i in range(len(deck))]