Python: What is wrong with the indexing logic in my code? - python

"You are given an array of n integers and an integer k. Find and print the number of (i,j) pairs where i<j and a[i] + a[j] is evenly divisible by k."
Sample input would be:
6 3
1 3 2 6 1 2
where 6 is n, 3 is k and the second line is the array of integers. The output for this input would be 5.
Here is my code, but i am not passing the test cases and am almost positive it has to do with how i am indexing it.
import sys
n,k = input().strip().split(' ')
n,k = [int(n),int(k)]
a = [int(a_temp) for a_temp in input().strip().split(' ')]
count=0;
for i in range(n):
curr = n-i
for j in range(curr):
if i < i + j:
if k % (a[i] + a[i+j]) ==0:
count = count + 1
print(count)
Also, followup question: Is this method i am approaching an efficient way of going about it?

you can try this ...
import sys
n,k = input().strip().split(' ')
n,k = [int(n),int(k)]
a = [int(a_temp) for a_temp in input().strip().split(' ')]
print(sum([1 for i in range(n) for j in range(i) if (a[i]+a[j])%k==0]))

k % ... means "k is divisible by ...", not "... is divisible by k".
if i < i + j is not very useful; you're better off doing what furas recommends in comments.

What you need is to make use of itertools.combinations:
from itertools import combinations
count = 0
for i, j in combinations(range(n), 2):
if i < j and (a[i] + a[j]) % k == 0:
print i, j
count += 1
Discussion
range(n) returns a list of indices 0 .. n-1
combinations(range(n), 2) will yield a list of two indices (without duplications)
(a[i] + a[j]) % k == 0 is the test that your asked
Note that combinations will yield pairs of i, j where i is always less than j, but the test i < j is there as a paranoid measure

Related

How do I print the distinct pairs of the target sum of the following program?

In the following program, I am getting the output in which the pair is repeating, could you please help me with how do I print only the unique pairs?
The following program is to print the pairs to the target sum. I have to get only "1 and 4" and "2 and 3" as the output. I should not get "4 and 1" in the output.
def printPairs(arr, n, sum):
for i in range(0, n ):
for j in range(i + 1, n ):
if (arr[i] + arr[j] == sum):
print("", arr[i], " and ", arr[j], "", sep = "")
arr = [5,1,2,3,4,1,5]
n = len(arr)
sum = 5
printPairs(arr, n, sum)
Current Output:
1 and 4
2 and 3
4 and 1
Required Output:
1 and 4
2 and 3
Store the pairs in a set:
def printPairs(arr, n, sum):
pairs = set()
for i in range(0, n ):
for j in range(i + 1, n ):
if (arr[i] + arr[j] == sum):
if arr[i] in pairs or arr[j] in pairs:
continue
else:
print("", arr[i], " and ", arr[j], "", sep = "")
pairs = pairs + {arr[i] + arr[j]}
arr = [5,1,2,3,4,1,5]
n = len(arr)
sum = 5
printPairs(arr, n, sum)
Current Output:
1 and 4
2 and 3
4 and 1
Required Output:
1 and 4
2 and 3
Try this:
def printPairs(arr, n, sum):
seen = []
for i in range(0, n):
for j in range(i + 1, n):
if (arr[i] + arr[j] == sum):
if not arr[i] in seen and not arr[j] in seen:
seen.append(arr[i])
seen.append(arr[i])
print("", arr[i], " and ", arr[j], "", sep="")
The easiest one I could think of using set. Save the elements as tuples to achieve maximum performance of O(1)
def printPairs(arr, n, sum):
my_set=set()
for i in range(0, n ):
for j in range(i + 1, n ):
if (arr[i] + arr[j] == sum) and tuple(sorted([arr[i],arr[j]])) not in my_set:
my_set.add(tuple(sorted([arr[i],arr[j]])))
print("", arr[i], " and ", arr[j], "", sep = "")
For further improving the performance I'd sort the array first and would check if the element is already greater than the sum if yes then I would use continue or break as per the situation. Here is the example
def printPairs(arr, n, sum):
arr.sort()
my_set=set()
for i in range(0, n ):
if i>sum: # Check before going inside the inner loop
continue
for j in range(i + 1, n ):
if (arr[i] + arr[j] > sum):
break; # break if the sum of elements is greater than expected sum
if (arr[i] + arr[j] == sum) and tuple(sorted([arr[i],arr[j]])) not in my_set:
my_set.add(tuple(sorted([arr[i],arr[j]])))
print("", arr[i], " and ", arr[j], "", sep = "")
You can use itertools.combinations:
import itertools
def printPairs(arr, n, total):
combinations = itertools.combinations(arr, 2)
viewed = []
for a, b in combinations:
if a + b == total:
if (a, b) not in viewed and (b, a) not in viewed:
viewed.append((a, b))
print(a, 'and', b)
arr = [5,1,2,3,4,1,5]
n = len(arr)
sum = 5
printPairs(arr, n, sum)
Some observations:
you don't need to pass n (the length of the array), you can simply get it from len(arr).
You should use a different than sum because it is a built-in function
You can also use a set to track the combinations without repetition:
import itertools
def printPairs(arr, n, total):
combinations = itertools.combinations(arr, 2)
viewed = set()
for a, b in combinations:
if a + b == total:
if (a, b) not in viewed and (b, a) not in viewed:
viewed.add((a, b))
print(a, 'and', b)
arr = [5,1,2,3,4,1,5]
n = len(arr)
sum = 5
printPairs(arr, n, sum)
Do this as the first thing in the function:
arr = list(set(arr))
n = len(arr)
set() converts your 'arr' list into a set, all duplicates are removed
list() converts the resulting set back into a list
This also makes 'n' argument redundant though.
You can do this simply. Remove the duplicates and sort the list.
Then iterate through the list until you get to half the target value.
For each list element, see whether the needed number is in the list.
O(N) solution.
arr = [5,1,2,3,4,1,5]
target = 5
# Clean the input: dedup and sort
arr = sorted(set(arr))
# For each element in the lower half of the list,
# see whether the needed amount is also in the list.
for pos, value in enumerate(arr):
need = target - value
if need < value:
break
if need in arr:
print(value, "and", need)
Output:
1 and 4
2 and 3

Mean, Median, and Mode in Python

I'm doing a statistical problem set in Python on Hackerrank. When I input a list of values to calculate the mode. It shows me a runtime error.
# Enter your code here. Read input from STDIN. Print output to STDOUT
N = int(input())
X = list(map(int, input().split()))
X.sort()
# Find the mean
mean = sum(X) / N
print(mean)
# Find the median
if N % 2 == 0:
median = (X[N//2] + X[N//2 - 1]) / 2
else:
median = X[N//2]
print(median)
# Find the mode
occurrence = list([1 for _ in range(N)])
for i in range(N):
for j in range(i+1, N):
if X[i] == X[j]:
occurrence += 1
if max(occurrence) == 1:
mode = min(X)
else:
mode = X[occurrence[max(occurrence)]]
print(mode)
When I take a 2500 input for X, it just shows me a runtime error.
This is the link to the test case
enter link description here
I use this when looking for mean, median, and mode
import numpy as np
from scipy import stats
n = int(input())
arr = list(map(int, input().split()))
print(np.mean(arr))
print(np.median(arr))
print(stats.mode(arr)[0][0])
You are trying to add 1 to occurence which is of list type:
Also, I'm sure this may be a copying mistake but your loop is incorrect:
for i in range(N):
for j in range(i+1, N):
if X[i] == X[j]:
occurrence += 1
# It will be
for i in range(N):
for j in range(i+1, N):
if X[i] == X[j]:
occurrence += 1
Then you might wanna change your occurrence to something like:
occurrence[i] += 1
# from
occurrence += 1
Hope this helps
I have run your code, here is the compile problem:
for i in range(N):
for j in range(i+1, N):
if X[i] == X[j]:
occurrence += 1
I think your meaning is if inside two for, like:
for i in range(N):
for j in range(i + 1, N):
if X[i] == X[j]:
occurrence += 1
but occurrence is list here, can't plus by one, I think you means to count the occurrence of int, and output the max one? you can use defaultdict or Counter here, but defaultdict is only in one loops.
# import collections
# import operator
# Find the mode
occurrence = collections.Counter(X)
# occurrence = collections.defaultdict(int)
#
# for i in range(N):
# occurrence[X[i]] += 1
mode = max(occurrence.items(), key=operator.itemgetter(1))[0]
print(mode)
Here is a Mean, Median, and Mode class.
import statistics
from collections import Counter
def median(list):
n = len(list)
s = sorted(list)
return (sum(s[n//2-1:n//2+1])/2.0, s[n//2])[n % 2] if n else None
def mean(list):
if len(list) == 0:
return 0
list.sort()
total = 0
for number in list:
total += number
return total / len(list)
def mode(list):
counter = Counter(list)
if len(counter) > 1:
possible_mode, next_highest = counter.most_common(2)
if possible_mode[1] > next_highest[1]:
return possible_mode[0]
return "None"

Can I pick a specific item from generator?

With:
def merge(a, b):
i = j = 0
total = len(a) + len(b)
while i + j < total:
if j == len(b) or (i < len(a) and a[i] <= b[j]):
yield a[i]
i += 1
else:
yield b[j]
j += 1
Can I just pick the third element from the generator or I have to iterate by next() three times?
You can use itertools.islice in combination with next. However this will consume steps in your generator so it's effectively the same as calling next three times and picking up the third value. It's just a more abstract way of doing it.
>>> from itertools import islice
>>> g = (i for i in range(10))
>>> next(islice(g, 2, 2 + 1))
2
>>> next(g)
3

Project Euler problem number 4

n = 0
for a in xrange(999, 100, -1):
for b in xrange(a, 100, -1):
x = a * b
if x > n:
s = str(a * b)
if s == s[::-1]:
n = a * b
print n
I have a question about this solution to the problem.
I know it is right but I am wondering why in the xrange(999,100,-1) the -1 is there
For the a and b for loops. Please explain. I am new to this :)
The third parameter to xrange() is the increment value. The default is 1, which means the counter will count in an increasing direction. To count in a decreasing direction, use -1. Your a counter will go from 999 to 101 (the xrange() iterator stops just before it reaches the second parameter value).
For future reference, see the xrange() documentation.
The -1 specifies a negative step. Thus moving from 999 descending to 100 (exclusive).
xrange function takes three arguments: start, stop and step.
It returns a range of numbers starting from start continuing to stop, but not including it. If 'start' is bigger than stop, negative step must be provided.
So basically xrange(999, 100, -1) will give you [999, 998, ..., 101]
It means that you are decreasing (hence the negative sign) in increments of 1, from 999 to 100
This is what I got for the project Euler #4 question:
def Palindrome(s):
if s == s[::-1]:
return True
else:
return False
i = 100
j = 100
greatest = 0
while (i <= 999):
while (j <= 999):
product = i * j
if (product > greatest and Palindrome(str(product))):
greatest = product
j += 1
j = 100
i += 1
print "Answer: " + str(greatest)
-M1K3
My Python solution:
container = []
for i in range(100, 999):
for j in range(100, 999):
num = i * j
if str(num) == str(num)[::-1]:
container.append(num)
print(max(container))
__author__ = 'shreysatapara'
f=0
for a in range(100,1000):
for b in range(100,1000):
c=a*b
d=c
s=0
x=0
for i in range(0,len(str(c))):
s=c%10
x=x*10+s
c=c//10
if(x==d):
if(x>f):
f=x
print(f)
bingo answer is your last number in compiler....
import time
start_time = time.time()
largest_number = 0
for i in range(999,100,-1):
for j in range(i,100,-1):
string_number = str(i * j)
if string_number == string_number[::-1]:
if i*j > largest_number:
largest_number = i * j
print(largest_number)
print(time.time() - start_time," seconds")
The negative one is the modifier. Basically the loops start at 999, end at 100, and get there by modifying each number by negative one.
for x in range(100, 1000):
for y in range(100, 1000):
product = x*y
if product > x*y:
break
if str(product) == str(product)[::-1] and product > 900000:
print (x, y, product)
def reverse(s):
str = ""
for i in s:
str = i + str
return str
MAXN = 0
for i in range(100, 1000):
for j in range(100, 1000):
a = i * j
b = str(a)
if b == reverse(b) and a > MAXN:
MAXN = a
print(MAXN)

finding divisors of N using a list comprehension

I have started to write some Python code. What I have is:
from math import *
def ex(N):
l = []
sum = 0
N = abs(int(N));
for n in range(1,N):
if N % n == 0:
l.append(n)
sum += n
l.append(N)
print ' of '+str(N),l
print 'SUM', (sum+N)
I don't know if this is good or bad, but it is what I have tried :)
Is it possible to replicate the behavior of my code with list comprehension? If so, how?
l = [n for n in range(1,N+1) if N % n == 0]
total = sum(l)
Very simply (this actually uses a generator expression rather than a list comprehension, if you don't need to keep the results).
def ex(N):
N = abs(int(N))
print 'SUM', sum(n for n in xrange(1, N + 1) if N % n == 0)
If you care about the list, then instead:
def ex2(N):
N = abs(int(N))
l = [n for n in xrange(1, N + 1) if N % n == 0]
print ' of '+str(N),l
print 'SUM', sum(l)
You might find the Dive Into Python 3 explanation of list comprehensions useful, or if you've got some free hours, try watching an introductory Python tutorial.
You can do it with list-comprehension:
def ex(N):
N = abs(int(N))
l = [n for n in range(1, N + 1) if N % n == 0]
print ' of '+str(N),l
print sum(l)
You will keep the n for each n in the range from 1 to N(inclusive) if the condition(N % n == 0) is true. You will keep the list in l and then the function sum calculates the sum of the list.
Whether it is good or bad using list comprehension is up to you, but it is usually used as it is efficient and compact. And if you don't need a list because you just need to use the values one after the other and only one time generators are recommended because they don't use memory.
You can use list comprehension to replace:
for n in range(1,N):
if N % n == 0:
l.append(n)
with:
[l.append(n) for n in range(1,N) if N % n == 0]
Whether it is good or bad, in this case, I'm not sure. I like to use them when I can, but for more complex cases sometimes I opt for the for loop for readability.
Edit: Sorry, maybe I should have given a complete example.
def ex(N):
l = []
N = abs(int(N));
[l.append(n) for n in range(1,N) if N % n == 0]
l.append(N)
print l
print sum(l)

Categories

Resources