Where am I going wrong with enumerate? - python

I know the answer is probably super simple, but I'm absolutely stuck on this short piece of code. The function has no effect on the input list when I run it.
def squareEven(array):
for idx, val in enumerate(array):
if idx % 2 == 0:
val = val * val
else:
val = val
return array
array = [1, 2, 4, 9, 20]
print(squareEven(array))

You can also use the list comprehension to construct a new list with squared values when the index is even.
def squareEven(array):
return [v**2 if i % 2 == 0 else v for (i, v) in enumerate(array)]
https://docs.python.org/3/tutorial/datastructures.html#list-comprehensions

Here are two ways, one bad, one good:
def squareEven(array):
for idx in range(len(array)):
if idx % 2 == 0:
array[idx] = array[idx] * array[idx]
return array
array = [1, 2, 4, 9, 20]
print(squareEven(array))
This is better, because it doesn't damage the original array as a side effect:
def squareEven(array):
new = []
for idx,val in enumerate(array):
if idx % 2 == 0:
new.append(val * val)
else:
new.append(val)
return new
array = [1, 2, 4, 9, 20]
print(squareEven(array))

The reason is that the enumerate function does not actually change the array itself but just returns the new one for you to use in the loop. The simple solution is to save the enumerate(array) into another variable and return it at the end of your function. Keep in mind, you will get an enumerated array at the end. You could map it to convert to a form you initially passed.
In the function, you wrote you don't save the actual result. The variable val you used is temporary and changing it doesn't affect the array you passed. It means that val has the value from the array but not reference to the element. To solve the issue, you can directly change the element by referencing it with idx.

Related

Merging two sorted arrays in python

I am trying to merge two sorted arrays recursively, and I can merge the first few numbers until one pointer exits the array. There seems to be some problem with the base case not getting executed. I have tried to print the new_arr with the pointers for each recursive call to debug but cannot seem to find a solution. Here is my code:
new_arr= []
i= 0
j=0
def merge(arr1, arr2, i, j):
#base case
##when arr1 pointer exits
print(i,j, new_arr)
if(i>len(arr1)-1):
new_arr.append(arr2[j:])
return new_arr
##when arr2 pointer exits
if (j > len(arr2)-1):
new_arr.append(arr1[i:])
return new_arr
if(arr1[i]<arr2[j]):
new_arr.append(arr1[i])
i+=1
merge(arr1, arr2, i, j)
elif(arr1[i]>=arr2[j]):
new_arr.append(arr2[j])
j+=1
merge(arr1, arr2, i, j)
sortedarr = merge([1,9], [3,7,11,14,18,99], i, j)
print(sortedarr)
and here goes my output:
0 0 []
1 0 [1]
1 1 [1, 3]
1 2 [1, 3, 7]
2 2 [1, 3, 7, 9]
None
These are the issues:
new_arr.append(arr2[j:]) should be new_arr.extend(arr2[j:]). append is for appending one item to the list, while extend concatenates a second list to the first. The same change needs to happen in the second case.
As you count on getting the mutated list as a returned value, you should not discard the list that is returned by the recursive call. You should return it back to the caller, until the first caller gets it.
It is a bad idea to have new_arr a global value. If the main program would call the function a second time for some other input, new_arr will still have its previous values, polluting the result of the next call.
Although the first two fixes will make your function work (for a single test), the last issue would best be fixed by using a different pattern:
Let the recursive call return the list that merges the values that still needed to be analysed, i.e. from i and j onwards. The caller is then responsible of prepending its own value to that returned (partial) list. This way there is no more need of a global variable:
def merge(arr1, arr2, i, j):
if i >= len(arr1):
return arr2[j:]
if j >= len(arr2):
return arr1[i:]
if arr1[i] < arr2[j]:
return [arr1[i]] + merge(arr1, arr2, i + 1, j)
else:
return [arr2[j]] + merge(arr1, arr2, i, j + 1)
sortedarr = merge([1,9], [3,7,11,14,18,99], i, j)
print(sortedarr)
Note that Python already has a built-in function that knows how to merge sorted arrays, heapq.merge.
list(heapq.merge((1, 3, 5, 7), (2, 4, 6, 8)))
[1, 2, 3, 4, 5, 6, 7, 8]

How to return the first item rather than the entire list, using list comprehension?

I'm solving a problem where I must find an unique integer in a list, which is easily solvable using list.count(x). However, I'm having trouble condensing the code into one line.
def find_uniq(arr):
return [x for x in arr if arr.count(x) == 1]
My code works fine, but it returns for example: [2] instead of 2, or [0.55] instead of 0.55.
Is there a way to return the integer instead of the list containing the integer, using list comprehension?
You have already the answers for list-comprehension -- which is a waste of resources.
Your approach, though, is valid since it makes use of everyday/beginner structures. In the same argument, I would like to suggest two things:
avoid the redundant calls to count();
avoid the creation of a list (since all you want is one element a time).
Suppose we have the following array arr:
> arr = [random.randint(0,9) for _ in range(10)]
> arr
[6, 7, 0, 9, 3, 3, 3, 9, 8, 8]
To the first point, you can create a set to reduce the number of counts:
> numbers_set = set(arr)
> numbers_set
{0, 3, 6, 7, 8, 9}
Then you can have a generator with the help of our friend filter:
> unique_numbers = filter(lambda x:arr.count(x)==1, numbers_set)
> print(next(unique_numbers))
0
> print(next(unique_numbers))
6
> print(next(unique_numbers))
7
> print(next(unique_numbers))
StopIteration:
Instead of a list comprehension which produces a list, create a generator from which you take the first element:
return next(x for x in arr if arr.count(x) == 1)
This raises a StopIteration is no element in the list fulfils the criteria; you can instead return a default value like None like so:
return next((x for x in arr if arr.count(x) == 1), None)
It's also questionable whether it's wise to iterate the array again and again with count; depending on its size, that can be very inefficient. It may be more efficient to build a counter first:
from collections import Counter
return next(v for v, c in Counter(arr).items() if c == 1)
If you are sure that You want to return only one integer from the passed list You can change the return to
def find_uniq(arr):
return [x for x in arr if arr.count(x) == 1][0]
But it will return only first element that is unique in the list. If You want to return more of them the list is better approach
Return using indexing.
def find_uniq(arr):
return [x for x in arr if arr.count(x) == 1][0]

Python - How to check if the next value in a list is the same as the previous?

Let's say we have this array:
arr2 = [2, 3, 1, 2, 2]
I've tried the following:
for i,x in enumerate(arr2):
if x == 2 and x[i+1] == 2:
print('TwosPair')
But receiving the following error:
TypeError: 'int' object is not subscriptable
Shouldn't I be able to check the previous index / next one, using enumerate?
I also tried the following:
for i,x in enumerate(arr2):
if x == 2 and x[arr2.index(i)+1] == 2:
print('TwosPair')
But getting this error now:
ValueError: 0 is not in list
What 0 is it talking about?
You are a bit unclear, however if you want to check if the previous index has the same value as the next index relative. Zip will allow you iterate over the two lists the frist is the original and the second is sliced to be one element a head since is its frist item is one index ahead the original allowing to access the current and next indexes of the original list
def TwosPair(list_1):
for curr, next in zip(list_1, list_1[1:]):
if curr == 2 and next == 2: print('TwosPair')
arr2 = [2, 3, 3, 1, 2, 2, 9, 4, 4]
for i in range(len(arr2)-1):
if arr2[i] == arr2[i+1]:
print('Same next & current values!')
you can use this to find the current and next values when both of them have the same value.
Does this do what you need it to?
arr2 = [2, 3, 1, 2, 2]
for i,x in enumerate(arr2):
if i < len(arr2)-1 and arr2[i+1] == x:
print('TwosPair')
This accepts any iterable,
including generators and containers such as a list,
and reports on whether two adjacent elements are equal.
from typing import Iterable
def has_adjacent_dup(a: Iterable):
sentinel = object() # might use None if None won't appear in input
prev = sentinel
for i in a:
if prev == i:
return True
prev = i
return False
if has_adjacent_dup(arr2):
print('Pair')
You can use zip():
arr2 = [2, 3, 1, 2, 2]
for x,y in zip(arr2,arr2[1:]):
if x == y == 2:
print('TwosPair')
Output:
TwosPair
To answer your specific question, the 0 it is talking about is the 0 value that i takes in the first iteration of the enumerate generator and then when it tries to find that i in the array via arr2.index(i), it throws an error
I believe your approach is basically sound -- we just need to tweak it a little. First, we're going to use the second argument to enumerate() to make its generated value the next index. Second, we're going to limit the array loop to all but the last item so we don't overflow the array indicies. Finally, we'll use some fun Python syntax to simplify the test:
array = [2, 3, 1, 2, 2]
for next_index, element in enumerate(array[:-1], 1):
if element == 2 == array[next_index]:
print('TwosPair')
One efficient implementation of this requirement in Python is to use itertools.groupby.
from itertools import groupby
for k, g in groupby(arr):
if k == 2:
next(g)
for _ in g:
print("TwosPair")

How to get the index of specific item in python matrix

I am newbie to Python programming language. And I am looking for How to get the indexes (line and column ) of specific element in matrix.
In other I way I want to do the same as this source code using lists.
myList=[1,10,54,85]
myList.index(54)
Best Regards
Here's a simple function which returns the coordinates as a tuple (or None if no index is found). Note that this is for 2D matrices, and returns the first instance of the element in the matrix.
(Edit: see hiro protagonist's answer for an alternative Pythonic version)
def find(element, matrix):
for i in range(len(matrix)):
for j in range(len(matrix[i])):
if matrix[i][j] == element:
return (i, j)
Or, if you want to find all indexes rather than just the first:
def findall(element, matrix):
result = []
for i in range(len(matrix)):
for j in range(len(matrix[i])):
if matrix[i][j] == element:
result.append((i, j))
return result
You can use it like so:
A = [[5, 10],
[15, 20],
[25, 5]]
find(25, A) # Will return (2, 0)
find(50, A) # Will return None
findall(5, A) # Will return [(0, 0), (2, 1)]
findall(4, A) # Will return []
a (in my opinion) more pythonic version of FlipTack's algorithm:
def find(element, matrix):
for i, matrix_i in enumerate(matrix):
for j, value in enumerate(matrix_i):
if value == element:
return (i, j)
in python it is often more natural to iterate over elements of lists instead of just the indices; if indices are needed as well, enumerate helps. this is also more efficient.
note: just as list.index (without a second argument) this will only find the first occurrence.
Since you say that you're a beginner, pardon me if you already know some of the below. Just in case I'll describe the basic logic you can use to write your own function or understand the other answers posted here better:
To access an element in a specific row of a list, for example, if you wanted to get the first element and save it in a variable:
myList=[1,10,54,85]
myvar = myList[0] # note that you access the first element with index 0
myvar now stores 1. Why index 0? Think of the index as an indicator of "how far away from the beginning of the list an element is." In other words, the first element is a distance of 0 from the start.
What if you have a multi-dimensional list like so?
multi = [[0, 1, 2],
[3, 4, 5],
[6, 7, 8]
]
Now you think in terms of row and column (and of course you could have n-dimensional lists and keep going).
How to retrieve the 5? That is a distance of 1 row from the start of the list of rows and 2 columns away from the start of the sub-list.
Then:
myvar = multi[1][2]
retrieves the 5.
FlipTack's and hiro protagonist's functions wrap this logic in the nice compact procedures, which search the entire 2-dimensional list, comparing elements until the desired one is found, then returning a tuple of the indices or continuing to search for duplicate elements. Note that if your lists are guaranteed to sorted you can then use a binary search algorithm across rows and columns and get the answer faster, but no need to worry about that for now.
Hopefully this helps.
You can also add a tag to your function to search the occurrences of your input matrix/list.
For example:
If you input is 1D vector:
def get_index_1d(a = [], val = 0, occurrence_pos = False):
if not occurrence_pos:
for k in range(len(a)):
if a[k] == val:
return k
else:
return [k for k in range(len(a)) if a[k] == val]
Output:
a = [1,10,54,85, 10]
index = get_index_1d(a, 10, False)
print("Without occurrence: ", index)
index = get_index_1d(a, 10, True)
print("With occurrence: ", index)
>>> Without occurrence: 1
>>> With occurrence: [1, 4]
For 2D vector:
def get_index_2d(a = [], val = 0, occurrence_pos = False):
if not occurrence_pos:
for k in range(len(a)):
for j in range(len(a[k])):
if a[k][j] == val:
return (k, j)
else:
return [(k, j) for k in range(len(a)) for j in range(len(a[k])) if a[k][j] == val]
Output:
b = [[1,2],[3,4],[5,6], [3,7]]
index = get_index_2d(b, 3, False)
print("Without occurrence: ", index)
index = get_index_2d(b, 3, True)
print("With occurrence: ", index)
>>> Without occurrence: (1, 0)
>>> With occurrence: [(1, 0), (3, 0)]
Just wanted to throw another solution since I didn't see it above:
def find(matrix, value):
value_indexs = [ ( matrix.index(row), row.index(value) ) for row in matrix if value in row]
return value_indexs
Example:
matrix = [
[0, 1, 2],
[3, 4, 5, 6],
[7, 8, 9, 0]
]
find(matrix, 0)
Returns: [(0,0), (2,3)]

Recursion over one value, but storing lists along the way

My question is i have a function as follows:
def myfunc(a):
b=[]
b.append(a)
return myfunc(a-1), b*
*= I am aware this will break my function
is there any possible way to allow b to update with my used a values while having my function continue running? The code to which the question pertains is a max val. proble. So i have a list of weights and values, and a max. allowable weight. My function finds the max no problem, but I'd like to see what values i'm using to get there. i.e. w=[1,2,3] v=[4,7,2]
max weight= 3, max val is = 11. What I'd like my function to display in edition are list such as weights used=[1,2] and values used=[4,7]. Sorry for the lack of actual code posted, the site is not allowing it.
I suggest using a default argument.
def myfunc(a, lst=None):
if lst is None:
lst = []
lst.append(a)
if a > 0:
myfunc(a-1, lst)
return lst
print(myfunc(5)) # prints: [5, 4, 3, 2, 1, 0]
You mean, something like this?
def myfunc(a):
if a == 0:
return [a]
return myfunc(a-1) + [a]
myfunc(5)
> [0, 1, 2, 3, 4, 5]

Categories