what's wrong with my solution?Count of Maximum[Code Chef] - python

Question.This is simple question yet i don't know what's wrong with this code?
from collections import Counter
def com(N,A):
num_array=A.split()
c=Counter(num_array)
C=max(c.values())
l1=[]
for k in c:
if c[k]==C:
l1.append(k)
V1=min(l1)
V=int(V1)
print V,C
t=input()
for i in range(t):
N=input()
A=raw_input()
com(N,A)
If possible any simpler solution would be great

You need to convert the values in l1 to integers before taking the min. Otherwise you are taking the min of strings.

This will get you started:
from collections import Counter
li='''2
5
1 2 3 2 5
6
1 2 2 1 1 2'''.splitlines()
c=Counter()
for e in [s.split(' ') for s in li]:
c.update(e)
print c.most_common(2)
Prints:
[('2', 6), ('1', 4)]

Related

How can I restart a list once StopIteration exception is thrown or a certain point in list is reached? [duplicate]

It's my understanding that using a Generator is the best way to achieve something like this, but I'm open to suggestions.
Specifically, one use case is this: I'd like to print some items alongside another list, of an arbitrary length, truncating the initial iterator as necessary.
Here is working python code that demonstrates the exact example behavior I desire:
def loop_list(iterable):
"""
Return a Generator that will infinitely repeat the given iterable.
>>> l = loop_list(['sam', 'max'])
>>> for i in range(1, 11):
... print i, l.next()
...
1 sam
2 max
3 sam
4 max
5 sam
6 max
7 sam
8 max
9 sam
10 max
>>> l = loop_list(['sam', 'max'])
>>> for i in range(1, 2):
... print i, l.next()
...
1 sam
"""
iterable = tuple(iterable)
l = len(iterable)
num = 0
while num < l:
yield iterable[num]
num += 1
if num >= l:
num = 0
The Problem / My Question
As you may have noticed, this only works on lists/tuples/iterables that implement __getitem__ (if I'm not mistaken). Ideally, I'd like to be able to pass any iterable, and receive a generator that can properly loop over it's content.
If there's a better way to do something like this without a generator, I'm fine with that as well.
You can use itertools.cycle (source included on linked page).
import itertools
a = [1, 2, 3]
for element in itertools.cycle(a):
print element
# -> 1 2 3 1 2 3 1 2 3 1 2 3 ...
Try this-
L = [10,20,30,40]
def gentr_fn(alist):
while 1:
for j in alist:
yield j
a = gentr_fn(L)
print a.next()
print a.next()
print a.next()
print a.next()
print a.next()
print a.next()
print a.next()
>>gentr_fn(x,y)
10 20 30 40 10 20 30 ...
You can use module to keep it simple.
Just make sure not to start iterating from 0.
my_list = ['sam', 'max']
for i in range(1, 100):
print(my_list[(i % len(my_list))-1])
You can iterate over a list, appending an item to it:
somelist = [item1, item2, item3]
for item in somelist:
somelist.append(item)
do_something()

Python Comprehension - Replace Nested Loop

Working on the 'two-sum' problem..
Input: An unsorted array A (of integers), and a target sum t
The goal: to return a list of tuple pairs (x,y) where x + y = t
I've implemented a hash-table H to store the contents of A. Through use of a nested loop to iterate through H, I'm achieving the desired output. However, in the spirit of learning the art of Python, I'd like to replace the nested loop with a nice 1-liner using comprehension & a maybe lambda function? Suggestions?
Source Code:
import csv
with open('/Users/xxx/Developer/Algorithms/Data Structures/_a.txt') as csvfile:
csv_reader = csv.reader(csvfile, delimiter ='\n')
hash_table = {int(num[0]):int(num[0]) for(num) in csv_reader} #{str:int}
def two_sum(hash_table, target):
pairs = list()
for x in hash_table.keys():
for y in hash_table.keys():
if x == y:
continue
if x + y == target:
pairs.append((x,y))
return pairs
When you have two ranges and you want to loop both of them separately to get all the combinations as in your case, you can combine the loops into one using itertools.product. You can replace the code below
range1 = [1,2,3,4]
range2 = [3, 4, 5]
for x in range1:
for y in range2:
print(x, y)
with
from itertools import product
for x, y in product(range1, range2):
print(x, y)
Both code blocks produce
1 3
1 4
1 5
2 3
2 4
2 5
3 3
3 4
3 5
4 3
4 4
4 5
But you would still need the if check with this construct. However, what product returns is a generator and you can pass that as the iterable to map or filter along with a lambda function.
In your case you only want to include pairs that meet the criteria. Thus, filter is what you want. In my simple example, if we only want combinations whose sum is even, then we could do something like
gen = product(range1, range2)
f = lambda i: (i[0] + i[1]) % 2 == 0
desired_pairs = filter(f, gen)
This can be written as a one-liner like
desired_pairs = filter(lambda i: (i[0] + i[1]) % 2 == 0, product(range1, range2))
without being too complicated for being understood.
Note that like product and map, what filter returns is a generator, which is good if you are just going to loop over it later to do some other work. If you really need a list just do convert it to a list as
desired_pairs = list(filter(lambda i: (i[0] + i[1]) % 2 == 0, product(range1, range2)))
If we print this we get
[(1, 3), (1, 5), (2, 4), (3, 3), (3, 5), (4, 4)]

Merging intervals in Python

I am very new to Python programming and have come across a problem statement i have no clue how to solve.
I have four lines of input:
0 1
2 4
6 7
3 5
For accepting these 4 lines of input i can do the below:
for i in range(4):
a,b = list(map(int,input().split(' ')))
I am supposed to merge the intervals into(Output) :
0 1
2 5
6 7
Intervals (2,4) and (3,5) they should be merged into one (2,5).
I am not sure how should i go about this ?
Can someone help me in getting a direction?
Thanks in advance.
If you're looking for a Python library that handles intervals arithmetic, consider python-interval. Disclaimer: I'm the maintainer of that library.
import intervals as I
interval = I.empty()
for i, j in [(0, 1), (2, 4), (6, 7), (3, 5)]:
interval = interval | I.closed(i, j)
print(interval)
results in
[0,1] | [2,5] | [6,7]
See its documentation for more information.
Try this
from functools import reduce
# inp = [(0,1),(2,9),(6,7),(3,5)]
inp = [(0,1),(2,4),(6,7),(3,5)]
print(inp)
def merge(li,item):
if li:
if li[-1][1] >= item[0]:
li[-1] = li[-1][0], max(li[-1][1],item[1])
return li
li.append(item)
return li
print(reduce(merge, sorted(inp), []))

Comparing two CSV files in Python when rows have multiple values

I have two CSV files that I want to compare one looks like this:
"a" 1 6 3 1 8
"b" 15 6 12 5 6
"c" 7 4 1 4 8
"d" 14 8 12 11 4
"e" 1 8 7 13 12
"f" 2 5 4 13 9
"g" 8 6 9 3 3
"h" 5 12 8 2 3
"i" 5 9 2 11 11
"j" 1 9 2 4 9
So "a" possesses the numbers 1,6,3,1,8 etc. The actual CSV file is 1,000s of lines long so you know for efficiency sake when writing the code.
The second CSV file looks like this:
4
15
7
9
2
I have written some code to import these CSV files into lists in python.
with open('winningnumbers.csv', 'rb') as wn:
reader = csv.reader(wn)
winningnumbers = list(reader)
wn1 = winningnumbers[0]
wn2 = winningnumbers[1]
wn3 = winningnumbers[2]
wn4 = winningnumbers[3]
wn5 = winningnumbers[4]
print(winningnumbers)
with open('Entries#x.csv', 'rb') as en:
readere = csv.reader(en)
enl = list(readere)
How would I now search cross reference number 4 so wn1 of CSV file 2 with the first csv file. So that it returns that "b" has wn1 in it. I imported them as a list to see if I could figure out how to do it but just ended up running in circles. I also tried using dict() but had no success.
If I understood you correctly, you want to find the first index (or all indexes) of numbers in entries that are winning. If you want it, you can do that:
with open('winningnumbers.csv', 'rb') as wn:
reader = csv.reader(wn)
winningnumbers = list(reader)
with open('Entries#x.csv', 'rb') as en:
readere = csv.reader(en)
winning_number_index = -1 # Default value which we will print if nothing is found
current_index = 0 # Initial index
for line in readere: # Iterate over entries file
all_numbers_match = True # Default value that will be set to False if any of the elements doesn't match with winningnumbers
for i in range(len(line)):
if line[i] != winningnumbers[i]: # If values of current line and winningnumbers with matching indexes are not equal
all_numbers_match = False # Our default value is set to False
break # Exit "for" without finishing
if all_numbers_match == True: # If our default value is still True (which indicates that all numbers match)
winning_number_index = current_index # Current index is written to winning_number_index
break # Exit "for" without finishing
else: # Not all numbers match
current_index += 1
print(winning_number_index)
This will print the index of the first winning number in entries (if you want all the indexes, write about it in the comments).
Note: this is not the optimal code to solve your problem. It's just easier to undestand and debug if you're not familiar with Python's more advanced features.
You should probably consider not abbreviating your variables. entries_reader takes just a second more to write and 5 seconds less to understand then readere.
This is the variant that is faster, shorter and more memory efficient, but may be harder to understand:
with open('winningnumbers.csv', 'rb') as wn:
reader = csv.reader(wn)
winningnumbers = list(reader)
with open('Entries#x.csv', 'rb') as en:
readere = csv.reader(en)
for line_index, line in enumerate(readere):
if all((line[i] == winningnumbers[i] for i in xrange(len(line)))):
winning_number_index = line_index
break
else:
winning_number_index = -1
print(winning_number_index)
The features that might me unclear are probably enumerate(), any() and using else in for and not in if. Let's go through all of them one by one.
To understand this usage of enumerate, you'll need to understand that syntax:
a, b = [1, 2]
Variables a and b will be assigned according values from the list. In this case a will be 1 and b will be 2. Using this syntax we can do that:
for a, b in [[1, 2], [2, 3], ['spam', 'eggs']]:
# do something with a and b
in each iteration, a and b will be 1 and 2, 2 and 3, 'spam' and 'eggs' accordingly.
Let's assume we have a list a = ['spam', 'eggs', 'potatoes']. enumerate() just returns a "list" like that: [(1, 'spam'), (2, 'eggs'), (3, 'potatoes')]. So, when we use it like that,
for line_index, line in enumerate(readere):
# Do something with line_index and line
line_index will be 1, 2, 3, e.t.c.
any() function accepts a sequence (list, tuple, e.t.c.) and returns True if all the elements in it are equal to True.
Generator expression mylist = [line[i] == winningnumbers[i] for i in range(len(line))] returns a list and is similar to the following:
mylist = []
for i in range(len(line)):
mylist.append(line[i] == winningnumbers[i]) # a == b will return True if a is equal to b
So any will return True only in cases when all the numbers from entry match the winning numbers.
Code in else section of for is called only when for was not interrupted by break, so in our situation it's good for setting a default index to return.
Having duplicate numbers seems illogical but if you want to get the count of matched numbers for each row regardless of index then makes nums a set and sum the times a number from each row is in the set:
from itertools import islice, imap
import csv
with open("in.txt") as f,open("numbers.txt") as nums:
# make a set of all winning nums
nums = set(imap(str.rstrip, nums))
r = csv.reader(f)
# iterate over each row and sum how many matches we get
for row in r:
print("{} matched {}".format(row[0], sum(n in nums
for n in islice(row, 1, None))))
Which using your input will output:
a matched 0
b matched 1
c matched 2
d matched 1
e matched 0
f matched 2
g matched 0
h matched 1
i matched 1
j matched 2
presuming your file is comma separated and you have a number per line in your numbers file.
If you actually want to know which numbers if any are present then you need to iterate over the number and print each one that is in our set:
from itertools import islice, imap
import csv
with open("in.txt") as f, open("numbers.txt") as nums:
nums = set(imap(str.rstrip, nums))
r = csv.reader(f)
for row in r:
for n in islice(row, 1, None):
if n in nums:
print("{} is in row {}".format(n, row[0]))
print("")
But again, I am not sure having duplicate numbers makes sense.
To group the rows based on how many matches, you can use a dict using the sum as the key and appending the first column value:
from itertools import islice, imap
import csv
from collections import defaultdict
with open("in.txt") as f,open("numbers.txt") as nums:
# make a set of all winning nums
nums = set(imap(str.rstrip, nums))
r = csv.reader(f)
results = defaultdict(list)
# iterate over each row and sum how many matches we get
for row in r:
results[sum(n in nums for n in islice(row, 1, None))].append(row[0])
results:
defaultdict(<type 'list'>,
{0: ['a', 'e', 'g'], 1: ['b', 'd', 'h', 'i'],
2: ['c', 'f', 'j']})
The keys are numbers match, the values are the rows ids that matched the n numbers.

How can I infinitely loop an iterator in Python, via a generator or other?

It's my understanding that using a Generator is the best way to achieve something like this, but I'm open to suggestions.
Specifically, one use case is this: I'd like to print some items alongside another list, of an arbitrary length, truncating the initial iterator as necessary.
Here is working python code that demonstrates the exact example behavior I desire:
def loop_list(iterable):
"""
Return a Generator that will infinitely repeat the given iterable.
>>> l = loop_list(['sam', 'max'])
>>> for i in range(1, 11):
... print i, l.next()
...
1 sam
2 max
3 sam
4 max
5 sam
6 max
7 sam
8 max
9 sam
10 max
>>> l = loop_list(['sam', 'max'])
>>> for i in range(1, 2):
... print i, l.next()
...
1 sam
"""
iterable = tuple(iterable)
l = len(iterable)
num = 0
while num < l:
yield iterable[num]
num += 1
if num >= l:
num = 0
The Problem / My Question
As you may have noticed, this only works on lists/tuples/iterables that implement __getitem__ (if I'm not mistaken). Ideally, I'd like to be able to pass any iterable, and receive a generator that can properly loop over it's content.
If there's a better way to do something like this without a generator, I'm fine with that as well.
You can use itertools.cycle (source included on linked page).
import itertools
a = [1, 2, 3]
for element in itertools.cycle(a):
print element
# -> 1 2 3 1 2 3 1 2 3 1 2 3 ...
Try this-
L = [10,20,30,40]
def gentr_fn(alist):
while 1:
for j in alist:
yield j
a = gentr_fn(L)
print a.next()
print a.next()
print a.next()
print a.next()
print a.next()
print a.next()
print a.next()
>>gentr_fn(x,y)
10 20 30 40 10 20 30 ...
You can use module to keep it simple.
Just make sure not to start iterating from 0.
my_list = ['sam', 'max']
for i in range(1, 100):
print(my_list[(i % len(my_list))-1])
You can iterate over a list, appending an item to it:
somelist = [item1, item2, item3]
for item in somelist:
somelist.append(item)
do_something()

Categories

Resources