Find maximum length of consecutive repeated numbers in a list - python

My question is how to find the maximum length of consecutive repeated numbers (or elements in general) in a list. I wrote the following function which works fine but I was wondering if there's a better way to do this or improve my code.
def longest(roll):
'''Return the maximum length of consecutive repeated elements in a list.'''
i = 0
M = 0 # The maximum length
while 0 <= i < len(roll):
c = 1 # Temporarily record the length of consecutive elements
for j in range(i+1, len(roll)):
if roll[j] != roll[i]:
i = j
break
c += 1
i += 1
if c > M:
M = c
if i == len(roll) - 1:
break
return M
By maximum length I mean the following:
[1, 1, 2, 2, 2, 4] should return 3 (2 repeated 3 times);
[1, 2, 1, 2, 1] should return 1 (1 and 2 only repeated once).

You can use itertools.
In [8]: import itertools
In [9]: z = [(x[0], len(list(x[1]))) for x in itertools.groupby(a)]
In [10]: z
Out[10]: [(1, 2), (2, 3), (3, 1)]
Tuples are in (item, count) format. If there are multiple runs of a given number, this will group them accordingly as well. See below.
In [11]: a = [1,1,1,1,1,2,2,2,2,2,1,1,1,3,3]
In [12]: z = [(x[0], len(list(x[1]))) for x in itertools.groupby(a)]
In [13]: z
Out[13]: [(1, 5), (2, 5), (1, 3), (3, 2)]
Getting the max value isn't that hard from here.
In [15]: max(z, key=lambda x:x[1])[1]
Out[15]: 5

longest_fragment = 0
current_fragment = 0
a = int(input())
last_input = a # why do I assign last_input here?
while a:
if a == last_input:
current_fragment += 1
else: # why is current_fragment assigned 1 in this clause?
if current_fragment > longest_fragment:
longest_fragment = current_fragment
current_fragment = 1
last_input = a
a = int(input())
longest_fragment = max(longest_fragment, current_fragment)
# why didn't i use max in the loop?
# why am I checking again down here anyway?
print('The longest fragment was:', longest_fragment)

Related

Returning a list of tuples of frequency, where did I do wrong?

I have to do an exercise that ask me to do a function that find the frequency of consecutive values on a list and return a list of tuples where I have to show how many times it was the repetition.
Input:
[1, 1, 1, 3, 5, 1, 1, 3, 3]
Output:
[(1,3) , (3,1) , (5,1) , (1,2) , (3,2)]
Code:
def empaquetar(l):
lista = []
for i in range(len(l)-1):
cont = 0
j = i + 1
while l[i] == l[j] and j<len(l)-1:
cont += 1
i += 1
j += 1
if cont > 0:
lista.append((l[i], cont + 1))
else:
lista.append((l[i],1))
return lista
Well, what I wrote does not quite exactly return what I want and I can't find a solution but I search a lot, for example the tool Counter from collection or something like. I need help, any suggestion?
Not thoroughly tested, but here is a try
prev_val = None
counter = 1
for curr_val in input_list:
if prev_val is not None:
if prev_val != curr_val:
output_list.append((prev_val, counter))
counter = 1
else:
counter += 1
prev_val = curr_val
output_list.append((prev_val, counter))
print (output_list)
from itertools import groupby
lista = [group[0], len(list(group[1])) for group in groupby(l)]
I have developed an algorithm with a time complexity of O(n) for this.
def consecutive(lst):
lst.append(0)
count = 1
result = []
for i, value in enumerate(lst):
if value == lst[min(len(lst) - 1, i + 1)]:
count += 1
else:
result.append((value, count))
count = 1
return result
Results
Let's try a few test cases for this function.
>>> lst = [1, 1, 1, 3, 5, 1, 1, 3, 3]
>>> consecutive(lst)
[(1, 3), (3, 1), (5, 1), (1, 2), (3, 2)]
Here is another test case to verify the code.
>>> lst = [1, 2, 5, 5, 3, 2, 2, 1]
>>> consecutive(lst)
[(1, 1), (2, 1), (5, 2), (3, 1), (2, 2), (1, 1)]
Use a second for loop to check how many times the number is there consecutively.
def empaquetar(l):
lista = []
for i in l:
cont = 1
for j in range(i+1, len(l)):
If l[j]==i:
cont += 1
else:
break
lista.append((i, cont))
return lista

Seating arrangement - How do i pick only the neighbors combinations

i used itertools.combinations to list all possible combinations of a list...but how do i pick only the neighbors so that the users are all together
list =[1,2,3,4,5,6,7,8,9,10,11,12]
occupied = [2,6,7,11]
remaining seats are available... Now how do i arrange two folks together always in the available seats..
1 0
3 4
5 0
0 8
9 10
0 12
the right combinations are (1,3) (3,4) (3,5) (8,9) (9,10) (10,12) (since its two folks..we can interchange them.. so two possible ways)... altogether at the moment i have 28...how do i remove the rest..any guidance would be appreciated
/*just added my code/
import numpy as np
import itertools
from itertools import permutations, combinations, combinations_with_replacement
def seatingarrangement (arr):
arry = arr.split(',')
larr = [int(x) for x in arry]
total = (larr[0])
occ = larr[1:]
totals = [x+1 for x in range(0,total)]
print(totals)
for val in totals:
if val in occ:
item= totals.index(val)
totals[item] = 0
print(totals)
#result = list(filter(lambda x: x!=0, totals))
result = [x for x in totals if x != 0]
print(result)
comb = combinations(result,2)
data = itertools.dropwhile(lambda x: x < 5, [3, 12, 7, 1, -5])
print(list(comb))
avl = []
#total there are 8 seats and two users are to be seated next to each other always ... #moreover the seats are not all consecutive
for i,x in enumerate(totals):
if (i+1)%2 == 0:
print('even#:',i+1,'is :',x)
data = itertools.dropwhile()
print(data)
else:
print('odd#:',i+1,'is :',x)
I'd suggest a method that verifies the validity of a pair, regarding the occupied list and the position
def is_pair_valid(pair, occupied_list):
# check occupied
x, y = min(pair), max(pair)
if x in occupied_list or y in occupied_list:
return False
# check neighbours
diff = y - x
return diff in (2, 1, -2) if x % 2 == 1 else diff in (2, -1, -2)
odd number : the other should be at distance +2, +1 or -2 (ex 3 with 1,4,5)
even number : the other should be at distance +2, -1 or -2 (ex 4 with 2,3,6)
Then
values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
occupied = [2, 6, 7, 11]
for p in filter(lambda x: is_pair_valid(x, occupied), combinations(values, r=2)):
print(p)
Gives the correct
(1, 3)
(3, 4)
(3, 5)
(8, 10)
(9, 10)
(10, 12)

Explain for loop

I was trying the below code. Kindly go through below code and help me understand what is the logic to get the below output.
I was trying to add only the first 10 values or first 9 values out of the given 11 values.
nums = [1,3,5,7,9,1,3,2,4,5,6]
def random(nums):
count = 0
for x in range(len(nums)-2):
count = count + x
return count
print("The random addition for above prog is")
print(random(nums))
output:
The random addition for above prog is
36
when I replaced with for x in range(len(nums)-2) i am getting below o/p
The random addition for above prog is
45
when I replaced with for x in range(len(nums)) i am getting below o/p
The random addition for above prog is
55
on what basis I should use the logic range(len(nums)-2) or range(len(nums)-3) in using the for loop.
You added index value that created by range, not list values.
count += x # this is one of [0,1...]
len and range's behavior is below.
len returns number of value list contains
>>> nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> len(nums)
11
range returns n length list start with 0(usable for list index)
>>> range(11)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
python's for takes one value from list, and do something and take next one value...
for i in [1,3,2]:
print(i)
1
3
2
If you want to take first 10 value of list and loop them, you can do below.
for i in range(10):
print(nums[i])
length of list can create range's arg 10 with below
len(nums) - 1
# => 11 - 1
# => 10
integrate them for first 10 values of list
for i in range(len(nums) - 1):
print(nums[i])
if you want sum random values
count = 0
>>> for i in range(len(nums) - 1):
... print(i, nums[i])
... count += nums[i]
...
(0, 1)
(1, 3)
(2, 5)
(3, 7)
(4, 9)
(5, 1)
(6, 3)
(7, 2)
(8, 4)
(9, 5)
>>> count
40
>>>
If you want to just sum first 10 value of list with loop, you can write below
count = 0
for x in nums[:10]:
count += x
nums[:10] returns list contains first 10 values of nums like [1,3,5,...8]

How to find how many times a number occurs in a list without using any in-built functions

I am trying to find how many times a number occurs in a list without using any in-built functions. The below code won't work:
a = [1,1,2,3,4,4,5]
for i in a:
c = 0
if a[i] == a[i]+1:
c =+1
print(c)
Num is the number you are looking for. Not sure if that is what you are want.
a = [1,1,1,1,2,3,4,4,5]
c = 0
num = 1;
for i in a:
if i == num:
c += 1
print(c)
Or this
a = [1,1,1,1,2,3,4,4,5]
b = []
t = 0
x = 0
while t < len(a):
c = 0
temp = a
for i in temp:
if i == x:
c += 1
b.append(c)
t += c
x += 1
print(b)
outputs [0, 4, 1, 1, 2, 1]
I'm surprised to see 3 answers with no use of a dictionary to solve this problem.
l = [1, 1, 2, 3, 4, 4, 5]
counts = {}
for x in l:
if x in counts:
counts[x] += 1
else:
counts[x] = 1
After running the above code, counts stores the number of occurrences of each item in list l with the items themselves (numbers, in this case) as keys.
>>> l = [1, 1, 2, 3, 4, 4, 5]
>>> counts = {}
>>> for x in l:
... if x in counts:
... counts[x] += 1
... else:
... counts[x] = 1
...
>>> counts
{1: 2, 2: 1, 3: 1, 4: 2, 5: 1}
An ugly but almost fun way I have seen this done is to loop through your list, find the maximum, create a list of that size, and then reloop through and increment the index in your new list as you hit your values.
a = [1,1,2,3,4,4,5]
max = -1
for i in a:
if i > max:
max = i
long_list = [0] * (max + 1) #create the list of the max size
for i in a:
long_list[i] = long_list[i] + 1
print(long_list)
output here is: [0, 2, 1, 1, 2, 1]
Again this is not space efficient at all but I enjoy the implementation as I think it is fun.
The issue with this implementation is if you have a list such as [1,2,3,545543,34]. Then your output will be a little wild printed that way and a lot of space is wasted.
Surprisingly this is easy if you know the max. I assumed your min=0 and max=5 (you can change)
a = [1,1,2,3,4,4,5]
freq=[0]*6 # assume 5 is your max
for i in a:
freq[i] += 1
print(freq)
print(freq[num])
DEFAULTDICT
if you dont know the max
from collections import defaultdict
a = [1,1,2,3,4,4,5,5,5,5,5,5,5]
d=defaultdict(int)
for i in a:
d[i] +=1
print(d)

The most frequent pattern of specific columns in Pandas.DataFrame in python

I know how to get the most frequent element of list of list, e.g.
a = [[3,4], [3,4],[3,4], [1,2], [1,2], [1,1],[1,3],[2,2],[3,2]]
print max(a, key=a.count)
should print [3, 4] even though the most frequent number is 1 for the first element and 2 for the second element.
My question is how to do the same kind of thing with Pandas.DataFrame.
For example, I'd like to know the implementation of the following method get_max_freq_elem_of_df:
def get_max_freq_elem_of_df(df):
# do some things
return freq_list
df = pd.DataFrame([[3,4], [3,4],[3,4], [1,2], [1,2], [1,1],[1,3],[2,2],[4,2]])
x = get_max_freq_elem_of_df(df)
print x # => should print [3,4]
Please notice that DataFrame.mode() method does not work. For above example, df.mode() returns [1, 2] not [3,4]
Update
have explained why DataFrame.mode() doesn't work.
You could use groupby.size and then find the max:
>>> df.groupby([0,1]).size()
0 1
1 1 1
2 2
3 1
2 2 1
3 4 3
4 2 1
dtype: int64
>>> df.groupby([0,1]).size().idxmax()
(3, 4)
In python you'd use Counter*:
In [11]: from collections import Counter
In [12]: c = Counter(df.itertuples(index=False))
In [13]: c
Out[13]: Counter({(3, 4): 3, (1, 2): 2, (1, 3): 1, (2, 2): 1, (4, 2): 1, (1, 1): 1})
In [14]: c.most_common(1) # get the top 1 most common items
Out[14]: [((3, 4), 3)]
In [15]: c.most_common(1)[0][0] # get the item (rather than the (item, count) tuple)
Out[15]: (3, 4)
* Note that your solution
max(a, key=a.count)
(although it works) is O(N^2), since on each iteration it needs to iterate through a (to get the count), whereas Counter is O(N).

Categories