Index value not in list - python

I need to write code that returns 2 index numbers of an array. The function takes 2 arguments, one is an array and the other is an integer.
I need to check if two of the values inside the array adds up to the integer and using the numbers inside the array only once.
Here is my code:
def func(a,b):
for i in a:
cnt = 0
while cnt < len(a):
if i + a[cnt] == b and i != a[cnt]:
return list([i,a[cnt]])
else:
cnt += 1
print(func([3,7,2,10,20],27))
My output for func([3, 7, 2, 10, 20], 27) is [7, 20].
This code shows that the loop can find the numbers which add up to the integer.
But when I do this:
def func(a,b):
for i in a:
cnt = 0
while cnt < len(a):
if i + a[cnt] == b and i != a[cnt]:
return a.index(i,a[cnt])
else:
cnt += 1
print(func([3,7,2,10,20],27))
I get the Value error: 7 not in list, which clearly is.
I've had this issue working with other exercises as well.
Am I doing something wrong or the index function isn't suppose to be used like that.
What would be an efficient way to return the index numbers without having to write another loop for it?

The second parameter to index that you're passing is actually the starting index on the list in which the search for the element will start (as you can see here). If you remove it, you'll see that it returns the first value you want (but not the second). It is relevant to note that the index method will only ever return the first occurrence of the value.
def func(a,b):
for i in a:
cnt = 0
while cnt < len(a):
if i + a[cnt] == b and i != a[cnt]:
return a.index(i)
else:
cnt += 1
print(func([3,7,2,10,20],27))
>>> 1
This happens because the value you're passing as the starting index (a[cnt]) is greater than the actual index of the number (1).
By removing it, you search through all the list, and find the correct value (remembering that Python uses zero-indexed iterators).
But since you want to return a list with both values, you need to explicitly state you want the index for each, such as:
def func(a,b):
for i in a:
cnt = 0
while cnt < len(a):
if i + a[cnt] == b and i != a[cnt]:
return [a.index(i), a.index(a[cnt])]
else:
cnt += 1
print(func([3,7,2,10,20],27))
>>> [1, 4]
You could achieve the same results using two for loops, however, in a cleaner way (also gave meaningful names to variables):
def find_indices_for_sum(array, sum_value):
for i in array:
for j in array:
if i + j == sum_value and i != j:
return [array.index(i), array.index(j)]
print(find_indices_for_sum([3,7,2,10,20],27))
>>> [1, 4]
If you want to be able to deal with equal numbers, you can change the comparison strategy altogether, using indices instead of values, since the former are unique in a list, but the latter are not. enumerate is a good option here, since it allows to iterate both through index and values at the same time in a clean way.
def find_indices_for_sum(array, sum_value):
for i, value_i in enumerate(array):
for j, value_j in enumerate(array):
if i != j and value_i + value_j == sum_value:
return [i, j]
print(find_indices_for_sum([3,3],6))
>>> [0, 1]

Related

How would I count all pairs in a list when they are all the same?

I am trying to count all pairs of numbers in a list. A pair is just two numbers that are the same. My current code looks like this.
def pairs(lst):
lst.sort()
count = 0
for x in range(len(lst)):
if x+1 < len(lst):
if lst[x] == lst[x+1]:
count +=1
return count
pairs([1, 1, 1, 1, 1])
What do I need to change to be able to have it count each pair of 1's?
The reason that the function gives the wrong value is that it is taking each item in the list and checking if the next value matches it. This will double count all non-endpoint values. Also looping with conditional statements is inefficient. It may be better to think of the problem as the sum of modulo 2 of the count of each distinct item in the list.
Try this:
Include incomplete pairs
import math
def count_pairs(a_list):
counter=0
for x in set(a_list):
counter += math.ceil(lst.count(x)/2)
print(counter)
Include only complete pairs
import math
def count_pairs(a_list):
counter=0
for x in set(a_list):
counter += math.floor(lst.count(x)/2)
print(counter)
Example:
lst=[1,1,1,1,1,2,2,2,2,2,3,3,3,4,4,5,6,5]
count_pairs(lst)
Output 1
11
Output 2
7
You can try this approach:
list = [1,1,1,1,1,1,2,2,3,3,4]
list.sort
# remove last element if len(list) is odd
if ( len(list) % 2 != 0 ) :
list.pop()
c = 0
# create an `iter` object to simplify comparisons
it = iter(list)
for x1 in it:
x2 = next(it)
if ( x1 == x2 ):
c += 1
print(c)
It wasn't clear to me if you only want "1", if this is the case, introduce a check for x1 or x2 greater than 1 and break the loop.
Code
def count_pairs(lst):
' Using generator with Walrus operator '
return sum(cnt*(cnt-1)//2 for element in set(lst) if (cnt:=lst.count(element)))
Test
print(count_pairs([1, 1, 1, 1, 1])) # Output: 10
print(count_pairs([1,1,1,1,1,2,2,2,2,2,3,3,3,4,4,5,6,5])) # Output: 25
Explanation
The number of pairs of a number in the list is found by:
count the frequency of the number in the list
counting its combinations taking 2 at a time (i.e. for frequency k, combinations = k*(k-1)//2
We sum the pairs count for each unique number in list (i.e. set(lst))
For clarity, the oneliner solution can be expanded to the following.
def count_pairs(lst):
cnt = 0
for element in set(lst):
frequency = lst.count(element) # frequency of element
cnt += frequency * (frequency - 1) //2 # accumulate count of pairs of element
return cnt

Looping through two lists, comparing one list against the other and return values

I have two lists that I want to compare. I want to loop through list one values and compare it to the values in list two. Im looking to return either 1, 0, or -1 based on if the value in list one is less than or equal to the value in list two.
For example, the value of 2 from list one would be assigned a value of 0 because it is greater than 0 and less than 3 from list two.
list_one = [0,2,5,0,3,7]
list_two = [0,3]
#loop through list one values
for j in list_one:
#loop through list two values
for k in list_two:
if float(j) <= k:
value = 1
break
elif float(j) <= k:
value = 0
break
else:
value = -1
print(value)
Actual Outcome:
1
1
-1
1
1
-1
Expected Outcome:
1
0
-1
1
0
-1
There were a few issues in your logic, I have changed them in the code attached below
list_one = [0,2,5,0,3,7]
list_two = [0,3]
#loop through list one values
for j in list_one:
#loop through list two values
value=0
for k in list_two:
if float(j) <= k:
value += 1
break
elif float(j) == k:
value += 0
break
else:
value += -1
if value > 1:
value = 1
elif value < -1:
value = -1
print(value)
Let me know if this fixes it for you, the problem statement wasn't very clear, I have modified this code according to my interpretation of the problem statement
#Logic errors aside, the biggest mistake in this code sample is your confusing use of #list_two. Clearly list_two must be a 2-element list: [min, max]. Any other structure #would be difficult to understand. Keep it as a list if you prefer but at the outset #decode list_two as follows:""
min_val = list_two[0]
max_val = list_two[1]
#Then loop j through list_one and apply this logic:
if j < min_val:
value = 1
elif j > max_val:
value = -1
else:
value = 0
#So basically lose the second loop (the k loop). And definitely remove the float() #references.

Why this code is not working for specific type of data?

def find_even_index(arr):
for a in arr:
b = arr.index(a)
if sum(arr[b+1:]) == sum(arr[:b]):
return b
return -1
find_even_index([20,10,30,10,10,15,35])
>>> -1
My code works for all type of data except when it encounters a same digit before or after the number. The index does not change for other 10. Why?
Just writing out the solution that #Barmar is suggesting in his comments (+1):
def find_even_index(array):
for index in range(len(array)):
if sum(array[:index]) == sum(array[index + 1:]):
return index
return -1
print(find_even_index([20, 10, 30, 10, 10, 15, 35]))
Alternatively, if we wanted to avoid so many calls to sum(), and make good use of enumerate(), we could try:
def find_even_index(array):
total = sum(array)
partial_sum = 0
for index, number in enumerate(array):
if total - partial_sum == number:
return index
partial_sum += number * 2
return -1
The list.index() function will only return the index of the specified object closest to the start of the list. You can instead use enumerate to iterate through the list alongside each object's index:
def find_even_index(arr):
for i, a in enumerate(arr): # For index, number in arr
b = i
if sum(arr[b+1:]) == sum(arr[:b]):
return b
return -1
print(find_even_index([20,10,30,10,10,15,35]))
Output:
3

Returning smallest positive int that does not occur in given list

Write a function that given an array of A of N int, returns the smallest positive(greater than 0) that does not occur in A.
I decided to approach this problem by iterating through the list after sorting it.
The value of the current element would be compared to the value of the next element. Because the list is sorted, the list should follow sequentially until the end.
However, if there is a skipped number this indicates the smallest number that does not occur in the list.
And if it follows through until the end, then you should just add one to the value of the last element.
def test():
arr = [23,26,25,24,28]
arr.sort()
l = len(arr)
if arr[-1] <= 0:
return 1
for i in range(0,l):
for j in range(1,l):
cur_val = arr[i]
next_val = arr[j]
num = cur_val + 1
if num != next_val:
return num
if num == next_val: //if completes the list with no skips
return arr[j] + 1
print(test())
I suggest that you convert to a set, and you can then efficiently test whether numbers are members of it:
def first_int_not_in_list(lst, starting_value=1):
s = set(lst)
i = starting_value
while i in s:
i += 1
return i
arr = [23,26,25,24,28]
print(first_int_not_in_list(arr)) # prints 1
You can do the following:
def minint(arr):
s=set(range(min(arr),max(arr)))-set(arr)
if len(s)>0:
return min(set(range(min(arr),max(arr)))-set(arr)) #the common case
elif 1 in arr:
return max(arr)+1 #arr is a complete range with no blanks
else:
return 1 #arr is negative numbers only
You can make use of sets to achieve your goal.
set.difference() method is same as relative complement denoted by A – B, is the set of all elements in A that are not in B.
Example:
Let A = {1, 3, 5} and B = {1, 2, 3, 4, 5, 6}. Then A - B = {2, 4, 6}.
Using isNeg() method is used to check whether given set contains any negative integer.
Using min() method on A - B returns the minimum value from set difference.
Here's the code snippet
def retMin(arrList):
min_val = min(arrList) if isNeg(arrList) else 1
seqList=list(range((min_val),abs(max(arrList))+2))
return min(list(set(seqList).difference(arrList)))
def isNeg(arr):
return(all (x > 0 for x in arr))
Input:
print(retMin([1,3,6,4,1,2]))
Output:
5
Input:
print(retMin([-2,-6,-7]))
Output:
1
Input:
print(retMin([23,25,26,28,30]))
Output:
24
Try with the following code and you should be able to solve your problem:
def test():
arr = [3,-1,23,26,25,24,28]
min_val = min(val for val in arr if val > 0)
arr.sort()
l = len(arr)
if arr[-1] <= 0:
return 1
for i in range(0,l):
if arr[i] > 0 and arr[i] <= min_val:
min_val = arr[i] + 1
return min_val
print(test())
EDIT
It seems you're searching for the the value grater than the minimum positive integer in tha array not sequentially.
The code it's just the same as before I only change min_val = 1 to:
min_val = min(val for val in arr if val > 0), so I'm using a lambda expression to get all the positive value of the array and after getting them, using the min function, I'll get the minimum of those.
You can test it here if you want

Python function with double condition

I'd like to create a function that returns the elements of a list on odd positions or the negative elements of a list.
My solution works with the first assertion, but the second generates an AssertionError, because returns [-1, -2, 1] instead of [-1, -2]. Any suggestions?
def solution(input):
output = []
for item in input:
if item < 0:
output.append(item)
elif not item % 2 == 0:
output.append(item)
return output
assert solution([0,1,2,3,4,5]) == [1,3,5]
assert solution([1,-1,2,-2]) == [-1,-2]
You want the numbers on odd positions, but your % check is checking the actual values in the list rather than their positions.
Try using enumerate to get the index alongside the value as you iterate through the list:
def solution(input):
output = []
for ix, item in enumerate(input):
if item < 0 or ix % 2 != 0:
output.append(item)
return output
Also for completeness purpose you may want to consider adding this to your already existing code:
if any(i < 0 for i in output):
return [i for i in output if i < 0]
, since it tests if a negative exists and return only those if so. The answer by HumphreyTriscuit is, however, the better solution from my point of view.
One line to define solution function:
def solution(input):
return [input[pos] for pos in range(len(input)) if not pos %2 == 0 or input[pos] < 0]
print solution([0,1,2,3,4,5,7])
print solution([1,-1,2,-2, -3])

Categories