Counting the number of consecutive 3s in a 2D list - python

My dataset which I imported into python as a list:
Is there a way I can count the largest number of consecutive 3s? Like in the first row, the output should be 5 as there are 5 consecutive 3s.
import csv
r = csv.reader(open('motor.csv'))
list_r = list(r)
for row in list_r:
print
count = 0
for col in row:
if col == '3' and row[row.index(col)+1] == '3':
count+=1
print count
This is the code I wrote but I seem to get incorrect output.

Consider using itertools.groupby to break the list into sub-sequences of identical values. Then simply return the maximum length of the sub-sequences.
from itertools import groupby
list_r = [
['3','3','3','3','3','1','3','3','5'],
['1','2','3','3','3','3','3','3','1','3','3','5','3'],
['3','2','3','3','3','3','3','3','1','3','3','5'],
]
result = [
max(len(list(g)) for k, g in groupby(row) if k == '3')
for row in list_r
]
assert result == [5, 6, 6]

They to use the following as a guide:
import itertools
def consecutive(group):
first, second = itertools.tee(group)
second.next()
for first, second in itertools.izip(first, second):
if second != first + 1: return False
return True
def iterate_submatrix(matrix, t, l):
'''yield the horizontals and diagonals of 4x4 subsection of matrix starting at t(op), l(eft) as 4-tuples'''
submat = [row[l:l+4] for row in matrix[t:t+4]]
for r in submat: yield tuple(r)
for c in range (0,4):
yield tuple(r[c] for r in submat)
yield tuple(submat[rc][rc] for rc in range (0,4))
yield tuple(submat[rc][3-rc] for rc in range(0,4))
for item in iterate_submatrix(test_matrix, 0,0):
print item, consecutive(item)

First, row.index(col) will always produce the index of the first value of col in the row. This is clearly not what was intended. Instead, I'd recommend using enumerate to iterate over the values and indices in the row at the same time.
Second, you are only tracking the current number of consecutive 3's, and there is no code to track the maximum of this count value. Adding another variable and an else clause to your code can resolve this.
for row in list_r:
max_count = current_count = 0
for index, value in enumerate(row[:-1]):
if value == '3' and row[index+1] == '3':
current_count += 1
else:
max_count = max(current_count, max_count)
current_count = 0
print count

import re
data = [
['1', '2', '2', '3', '5', '6'],
['1', '2', '3', '3', '4', '5'],
['1', '2', '3', '3', '3', '4']
]
max = 0
for item in data:
match = re.search(r'3+', "".join(item))
try:
if len(str(match.group(0))) > max:
max = len(str(match.group(0)))
except AttributeError:
pass
print(max)

Related

Looking for the fastest way to divide dictionary keys (based on values) into lists of list such that each list does not cross a certain threshold

I have an OrderedDictionary
a = {"1":800, "2":400, "3":600, "4":200, "5":100, "6":400}
I would like to divide the keys into a list of lists such that each list's total values do not exceed a threshold value (600 in this case) or if a value is greater than the threshold value it should have its own list. Also, we only check for the next key (like a sliding window).
The above dictionary should return expected = [['1'], ['2'], ['3'], ['4', '5'], ['6']]. For example, '1' has its own list since it is greater than threshold. '2' has its own list since values of '2' + '3' is greater than threshold. ['4', '5'] has values totalling up to 600 and if we append '6', it exceeds the threshold.
Here is what I have so far:
def check_result(a):
result = {}
curr_val = 0
threshold = 600
l =[]
result = []
for i in a.keys():
if curr_val >= threshold:
result.append(l)
l = []
curr_val = 0
if curr_val + a[i] > threshold:
result.append(l)
l = [i]
curr_val = a[i]
else:
l.append(i)
curr_val += a[i]
result.append(l)
print(result)
It gives the output as [[], ['1'], ['2'], ['3'], ['4', '5'], ['6']].
Looking for a correct solution in O(n) time.
Thanks!
The second if should just have an extra check that l is not empty:
if curr_val + a[i] > threshold and l:
Slightly less cumbersome code:-
a = {"1": 800, "2": 400, "3": 600, "4": 200, "5": 100, "6": 400}
def check_result(d):
T = 600
result, e = [], []
s = 0
for k, v in d.items():
if e:
if s + v > T:
result.append(e)
else:
e.append(k)
s += v
continue
e = [k]
s = v
if e:
result.append(e)
return result
print(check_result(a))
Based on the running sum, you can streamline the code by toggling the list to append keys to between the whole result and its last sublist.
a = {"1":800, "2":400, "3":600, "4":200, "5":100, "6":400}
t = 600 # Treshold
r = [] # result, list of lists of keys
s = 0 # running sum
for k,v in a.items():
group,item,delta = (r[-1],k,v) if r and s+v<=t else (r,[k],v-s)
group.append(item) # append to result or last sublist
s += delta # update running sum
print(r)
[['1'], ['2'], ['3'], ['4', '5'], ['6']]
Or this somewhat shorter (but less efficient) variant:
r,s = [],0 # result, running sum
for k,v in a.items():
r += [r.pop(-1)+[k] if r and s+v<=t else [k]]
s += v - s*(s+v>t)

How can the different elements of the list be multiplied (str and int)?

I am trying to get conversion of string like 'a3b4' to 'aaabbbb'.
How can this be done without additional modules? So far my code looks like this:
s = 'a3b4'
n = ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9')
a = []
b = []
for i in range(len(s)):
if s[i] in n:
a.append(s[i])
if s[i] not in n:
b.append(s[i])
for i in range(len(b)):
print(b[i])
This should work:
letters = list(s[::2])
nums = list(s[1::2])
res = ''.join([a*int(b) for a,b in zip(letters,nums)])
>>res
Out[1]: 'aaabbbb'
EDIT:
If you want to match any srting and any digits you should use regex:
letters = re.findall(r'[a-z]+',s)
nums = re.findall(r'\d+',s)
res = ''.join([a*int(b) for a,b in zip(letters,nums)])
for:
s='a10b3'
output is:
>>res
Out[2]: 'aaaaaaaaaabbb'

python list of list comparing elements

I want to compare element of lists. I parsed data from a text file but I couldn't compare the lists.
These are the lists which I got after parsing a text file:
[['Detected', '1', '-9.5', 'S19960'],['Active', '3', '-14.3', 'S19966'],
['Detected', '10788', '-10.5', 'S19961']]
[['Active', '2', '-16.3', 'S15620'],['Monitored', '2', '-18.2', 'S15629'],
['Detected', '2', '-8.8', 'S1003H'], ['Detected', '2', '-10.3', 'S02965'],
['Detected', '2', '-6.3', 'S56615'], ['Detected', '2', '-20.8', 'S10105'],
['Active', '2', '-20.8', 'S06940'], ['Detected', '2', '-17.8', 'S52835'],
['Detected', '2', '-20.8', 'S5198E'], ['Detected', '2', '-21.2', 'S56749'],
['Serving', '2', '-12.2', 'S02035'], ['Monitored', '2', '-24.5', 'S04919']]
The code will find Detected elements and will check if -9.5 (the second elements of lists) is bigger than -12. If it's bigger it will check Active and Servings elements.
For example -9.5 > -14.3, if the difference is bigger than 3, the output will be for the first list:
S19960 > S19966 | S19961 > S19966
for the second list:
S1003H > S15620,S06940,S02035 | S56615 > S15620,S06940,S02035
Here's a working implementation, which first finds the indexes of the relevant Detected elements (with value bigger than -12) and of the elements to be compared (Active and Serving elements). It then uses those indexes to parse and compare values in the list and generate an output string:
def comparisonFromList(data):
# find indexes of Detected elements with value > -12
detected = [i for i in range(len(data)) if data[i][0] in ['Detected'] and float(data[i][2]) > -12]
# find indexes of Active and Serving elements
tocompare = [i for i in range(len(data)) if data[i][0] not in ['Detected','Monitored']]
output = ""
for i,detect in enumerate(detected):
if i > 0:
output += ' | '
output += data[detect][3];
output += ' > '
for j,compare in enumerate(tocompare):
if abs(float(data[detect][2]) - float(data[compare][2])) > 3:
if 0 < j:
output += ','
output += data[compare][3];
return output
Output (based on the two input lists you provided):
> print(comparisonFromList(list1))
S19960 > S19966 | S19961 > S19966
> print(comparisonFromList(list2))
S1003H > S15620,S06940,S02035 | S02965 > S15620,S06940 | S56615 > S15620,S06940,S02035
Demo: https://repl.it/#glhr/55562796

Assigning words a unique number identifier

Task
I am trying to assign an number identifier for words in a string.
Code
I have currently done the following:
mystr = 'who are you you are who'
str_values = mystr.split()
list_values = [str(i) for i, w in enumerate(mystr.split())]
Output:
>>> str_values
['0', '1', '2', '3', '4', '5']
>>> list_values
['who', 'are', 'you', 'you', 'are', 'who']
Query/Desired Output
mystr contains repeating words, and so I would like to assign each word a number rather than different numbers each time but aren't sure how I should begin doing so. Therefore, I would like list_values to output something along the line of:
['0', '1', '2', '2', '1', '0']
You could do this with help of another list -
n = []
output = [n.index(i) for i in mystr.split() if i in n or not n.append(i)]
First n is empty list. Now list comprehension iterate over all the element of mystr.split(). It adds the index of the element in list n if condition met.
Now for the condition. There are two parts with an or. First it checks if the element is present in n. If yes, then get the index of the element. If no, it goes to the second part, which just appends the element to the list n. Now append() returns None. That is why I added a not before it. So, that condition will be satisfied and it will give the newly inserted elements index.
Basically the first part of if condition restricts duplicate element addition in n and the second part does the addition.
Well we can work in two phases:
first we construct a dictionary that maps words on indices, given they do not exist yet, and
next we use the dictionary to obtain the word identifiers.
Like:
identifiers = {}
idx = 0
for word in mystr.split():
if word not in identifiers:
identifiers[word] = idx
idx += 1
list_values = [identifiers[word] for word in mystr.split()]
This generates:
>>> [identifiers[word] for word in mystr.split()]
[0, 1, 2, 2, 1, 0]
If you want, you can also convert the identifiers to strings, with str(..), but I do not see why wou would do that:
>>> [str(identifiers[word]) for word in mystr.split()]
['0', '1', '2', '2', '1', '0']
The algorithm will usually work in O(n).
You need to use a dictionary to keep track of which words have already been seen
word_map = {}
word_id_counter = 0
def word_id(word):
global word_id_counter
if word in word_map:
return word_map[word]
else:
word_map[word] = word_id_counter
word_id_counter += 1
return word_map[word]
To avoid using global variables you can wrap it in a class
class WordIdGenerator:
word_map = {}
word_id_counter = 0
def word_id(self, word):
if word in self.word_map:
return self.word_map[word]
else:
self.word_map[word] = self.word_id_counter
self.word_id_counter += 1
return self.word_map[word]
And you can use it like this:
gen = WordIdGenerator()
[gen.word_id(w) for w in 'who are you you are who'.split()]
And the output will be:
[0, 1, 2, 2, 1, 0]

Learning Python: Changing value in list based on condition

Sorry for the very basic question, but this is actually a 2-part question:
Given a list, I need to replace the values of '?' with 'i' and the 'x' with an integer, 10. The list does not always have the same number of elements, so I need a loop that permits me to do this.
a = ['1', '7', '?', '8', '5', 'x']
How do I grab the index of where the value is equal to '?'. It'd be nice if this show me how I could grab all the index and values in a list as well.
Write a function for it and use map() to call it on every element:
def _replaceitem(x):
if x == '?':
return 'i'
elif x == 'x':
return 10
else:
return x
a = map(_replaceitem, a)
Note that this creates a new list. If the list is too big or you don't want this for some other reason, you can use for i in xrange(len(a)): and then update a[i] if necessary.
To get (index, value) pairs from a list, use enumerate(a) which returns an iterator yielding such pairs.
To get the first index where the list contains a given value, use a.index('?').
For 1:
for i in range(len(a)):
if a[i] == '?':
a[i] = 'i'
elif a[i] == 'x':
a[i] = 10
For 2, what do you mean by "key"? If you mean index:
index = a.index('?')
Only because no one's mentioned it yet, here's my favourite non-for-loop idiom for performing replacements like this:
>>> a = ['1', '7', '?', '8', '5', 'x']
>>> reps = {'?': 'i', 'x': 10}
>>> b = [reps.get(x,x) for x in a]
>>> b
['1', '7', 'i', '8', '5', 10]
The .get() method is incredibly useful, and scales up better than an if/elif chain.
Start by reading the Built-in Types section of the Library Reference. I think that you are looking for list.index.
it is function called 'index':
>>> a = ['1', '7', '?', '8', '5', 'x']
>>> a.index('?')
2
You can now use lambda
# replace occurrences of ?
a = map(lambda x: i if x == '?' else x, a)
# replace occurrences of x
a = list(map(lambda x: 10 if x == 'x' else x, a))
a = ['1', '7', '?', '8', '5', 'x']
for index, item in enumerate(a):
if item == "?":
a[index] = "i"
elif item == "x":
a[index = 10
print a

Categories