Python `arr[0]:[0]` explanation - python

This code snippet is one of posts in a LeetCode problem by fukuzawa_yumi
def splitArray(self, nums):
d,n={nums[0]:[0]},len(nums)
for i in range(1,n):
nums[i]+=nums[i-1]
if nums[i] not in d: d[nums[i]]=[i]
else: d[nums[i]].append(i)
for i in range(1,n-5):
for k in d.get(nums[-1]-nums[i-1],[]):
if i+3<k<n-1 and any(nums[i-1]+nums[j+1]==nums[k-1] for j in d.get(nums[i]+nums[i-1],[]) if i<j<k-2): return True
return False
The nums[0]:[0], d: d[nums[i]]=[i] are unfamiliar to me and I can't find explanation online.
Please, reference me in the right direction and give a few examples for posterity.

d,n={nums[0]:[0]},len(nums)
Is a somewhat ugly way of writing1:
d = {nums[0]: [0]}
n = len(nums)
It creates a dictionary d with a single item. The key is the first element in nums and the value is a one element list containing 0.
Later on, when you get to:
d[nums[i]] = [i]
This is a "replace-or-set" operation on the dictionary. The code is setting a dictionary item with key = nums[i] to a list with a single element whose value is i.
1In my subjective opinion :)

d,n={nums[0]:[0]},len(nums)
What this line is doing is:
bind d to a dictionary formed a single element with the key nums[0] (first element in list nums) and value [0] (a list containing 0)
bind n to the length of the list nums
It is possible to combine the two assignments on one line like this in Python. Python will perform the assignment of the variables based on the order. It's the same as doing tuple expansion.

Related

I cannot understand why this code is wrong

class Solution:
def firstRepeated(self,A, n):
#arr : given array
#n : size of the array
D={}
for i in range(n):
if A[i] not in D:
D[A[i]]=[i]
else:
D[A[i]].append(i)
c=0
for i in D:
if(len(D[i])>1):
c+=1
return (D[i][0]+1)
if(c==0): return -1
A=[1 ,5 ,3, 4, 3, 5, 6]
n=len(A)
M=Solution()
print(M.firstRepeated(A,n))
this is a problem from geeks for geeks.
" Given an array arr[] of size n, find the first repeating element. The element should occurs more than once and the index of its first occurrence should be the smallest"
the index positions(returned) are assumed to start from 1. If there is no
such element that has frequency more than 1 , we gotta return -1
This code is actually working correctly in VS code, but whenever I use
it in GFG IDE, it's failing(shows 3 as output instead of 2)
Kindly help, as I have no idea what's wrong here.
Your code is returning the index of the repeating element based on the order that keys are stored in the dictionary. After having collected all values in a dictionary keyed by number, your code iterates that dictionary like this:
for i in D:
The order in which this loop will visit the dictionary keys (indexes), depends on the Python version. See Are dictionaries ordered in Python 3.6+?.
At the time of writing Geeks for Geeks uses version 3.5.2, and so the order the keys are visited is undefined, which means that sometimes your function will not return the expected answer on their web site, while on your own environment it will always be correct (if you have a more recent version).
Correction
You can change your code so it does not rely on the order of the dictionary. Instead, during insertion, check which is the dictionary key with the least value. Here is your code corrected just with that change in mind:
class Solution:
def firstRepeated(self,A, n):
D = {}
c = len(A)
for i in range(n):
if A[i] not in D:
D[A[i]] = i # No need to maintain a list
elif D[A[i]] < c: # When the dupe's first index is earlier...
c = D[A[i]]
if c == len(A):
return -1
return c + 1
This will do the trick.
I checked in https://www.onlinegdb.com/online_python_compiler and works correctly.
it works also in https://ide.geeksforgeeks.org/

Write an generator/iterator expression for this sequence

I have this exercise that I fail to understand
Suppose we are given a list X of integers. We need to construct a sequence of indices (positions) of the elements in this list equal to the maximal element. The indicies in the sequence are in the ascending order.
Hint use the enumerator function
from typing import Iterator
X = [1,10,3,4,10,5]
S : Iterator[int] = YOUR_EXPRESSION
assert list(S)==[1,4]
This is the only thing I could come up with, but for sure it does not return [1,4]
If you wondering what I don't understand, it is not clear from reading the description how it could return [1,4].
Maybe you want to try to explain that to me first...
This is my (wrong) solution
my_enumerate=enumerate (X)
my_enumerate=(list(my_enumerate))
my_enumerate.sort(reverse=True)
So you have the list X containing [1,10,3,4,10,5]. The maximal, or largest, element is 10. Which means we should return a list of all the indices where we find 10. There are two 10s at index 1 and 4 respectively.
Using enumerate you get at each iteration the index and element. You can use that to filter out the elements you don't need. List comprehensions are useful in this case, allowing for filtering with the if syntax i.e. [val for val in items if some_condition]
you can use a generator like this
max_val=max(X)
s = (i for i, v in enumerate(X) if v==max_val)
This is my solution
( x[0] for x in enumerate (X) if x[1] == max(X) )
this is the book solution
(i for (i, n) in enumerate(X) if n == max(X))
This requires two steps:
Determine the maximum value with max
Iterate the indices of your list and retain those that have this maximum value
To avoid a bad time complexity, it is necessary to not repeat the first step:
S : Iterator[int] = (lambda mx:
(i for i, x in enumerate(X) if x == mx)
)(max(X))
The reason for presenting the code in such ugly expression, is that in the question it seems a requirement to follow the template, and only alter the part that is marked with "YOUR_EXPRESSION".
This is not how you would write it without such artificial constraints. You would just do mx = max(X) and then assign the iterator to S in the next statement without the need for this inline lambda.

Is this an example of call-by-reference, a bug, or something else? [duplicate]

This question already has answers here:
Are Python variables pointers? Or else, what are they?
(9 answers)
Closed 3 years ago.
I am writing a little program to create a list of permutations. I read about the algorithm on wikipedia.
My algorithm basically takes an initially sorted list of numbers, and permutes it in place. It then appends this new permutation to a list. When all permutations are found, it returns the list of lists containing all the permutations. It is very good at printing out the expected results, but when I try to add those results to a list, things get a little funny.
I noticed that every time I find the next permutation and append it to, the previous list elements get updated to the new permutation. So, at the end of it all, what gets returned is a list containing a bunch of copies of the same permutation (exactly the last permutation).
I've read that Python is pass by value, pass by reference and I've also read that it's neither. I'm not smart enough to argue with any of those people, but I am wondering why my program is doing this, and how to remedy it:
def lexi_order(nums):
permutations = []
length = len(nums)
while True:
# find largest index i such that nums[i] < nums[i + 1]
exists = False
for j, elem in enumerate(nums):
# check if last element
if j == length - 1:
break
if elem < nums[j + 1]:
i = j
exists = True
if not exists:
break
# find largest index k, such that i < k AND nums[i] < nums[k]
for j in range(i + 1, length):
if nums[j] > nums[i]:
k = j
# swap order of nums[i] and nums[k]
nums[i], nums[k] = nums[k], nums[i]
# reverse order of elements starting at position i+1
to_reverse = nums[i+1:][::-1]
nums[i+1::] = to_reverse
permutations.append(nums)
print(permutations)
return permutations
You're modifying the input (nums) in place each iteration through the loop, and then you keep adding a reference to the input to permutations. To fix it, make a copy of nums at the beginning of the loop and use it instead of the original everywhere inside it.
When you append nums to permutations, you are appending a reference to it, not copying all of the data over. When you modify nums, it gets modified everywhere. Python is pass by reference. If you make a change to a variable (not to be confused with reassigning it), that change will be reflected everywhere.
You need to make a copy of the passed nums, otherwise you are working on the passed reference. E.g.
def lexi_order(nums):
permutations = []
nums = list(nums) # We are now working on a copy, and won't mutate the original whatsoever.
length = len(nums)
...

Sorting for index values using a binary search function in python

I am being tasked with designing a python function that returns the index of a given item inside a given list. It is called binary_sort(l, item) where l is a list(unsorted or sorted), and item is the item you're looking for the index of.
Here's what I have so far, but it can only handle sorted lists
def binary_search(l, item, issorted=False):
templist = list(l)
templist.sort()
if l == templist:
issorted = True
i = 0
j = len(l)-1
if item in l:
while i != j + 1:
m = (i + j)//2
if l[m] < item:
i = m + 1
else:
j = m - 1
if 0 <= i < len(l) and l[i] == item:
return(i)
else:
return(None)
How can I modify this so it will return the index of a value in an unsorted list if it is given an unsorted list and a value as parameters?
Binary Search (you probably misnamed it - the algorithm above is not called "Binary Sort") - requires ordered sequences to work.
It simply can't work on an unordered sequence, since is the ordering that allows it to throw away at least half of the items in each search step.
On the other hand, since you are allowed to use the list.sorted method, that seems to be the way to go: calling l.sort() will sort your target list before starting the search operations, and the algorithm will work.
In a side note, avoid in a program to call anything just l - it maybe a nice name for a list for someone with a background in Mathematics and used to do things on paper - but on the screen, l is hard to disinguish from 1 and makes for poor source code reading. Good names for this case could be sequence lst, or data. (list should be avoided as well, since it would override the Python built-in with the same name).

Returning the index of the largest element in an array in Python

I'm trying to create a function that returns the largest element of an array, I feel I have the correct code but my syntax is in the wrong order, I'm trying to use a for/while loop in order to do so. So far I have the following:
def manindex(arg):
ans = 0
while True:
for i in range (len(arg)):
if arg[i] > arg[ans]:
pass
ans = i
return ans
Not sure where I'm going wrong if anyone could provide some guidance, thanks
EDIT: So it's been pointing out I'm causing an infinite loop so if I take out the while statement I'm left with
def manindex(arg):
ans = 0
for i in range (len(arg)):
if arg[i] > arg[ans]:
ans = i
return ans
But I have a feeling it's still not correct
When you say array I think you mean list in Python, you don't need a for/loop or while/loop to achieve this at all.
You can also use index with max, like so:
xs.index(max(xs))
sample:
xs = [1,123,12,234,34,23,42,34]
xs.index(max(xs))
3
You could use max with the key parameter set to seq.__getitem__:
def argmax(seq):
return max(range(len(seq)), key=seq.__getitem__)
print(argmax([0,1,2,3,100,4,5]))
yields
4
The idea behind finding the largest index is always the same, iterating over the elements of the array, compare to the max value we have at the moment, if it's better, the index of the current element is the maximum now, if it's not, we keep looking for it.
enumerate approach:
def max_element_index(items):
max_index, max_value = None, None
for index, item in enumerate(items):
if item > max_value:
max_index, max_value = index, item
return max_index
functional approach:
def max_element_index(items):
return reduce(lambda x,y: x[1] > y[1] and x or y,
enumerate(items), (None, None))[0]
At the risk of looking cryptic, the functional approach uses the reduce function which takes two elements and decides what is the reduction. Those elements are tuples (index, element), which are the result of the enumerate function.
The reduce function, defined on the lambda body takes two elements and return the tuple of the largest. As the reduce function reduces until only one element in the result is encountered, the champion is the tuple containing the index of the largest and the largest element, so we only need to access the 0-index of the tuple to get the element.
On the other hand if the list is empty, None object is returned, which is granted on the third parameter of the reduce function.
Before I write a long winded explanation, let me give you the solution:
index, value = max(enumerate(list1), key=lambda x: x[1])
One line, efficient (single pass O(n)), and readable (I think).
Explanation
In general, it's a good idea to use as much of python's incredibly powerful built-in functions as possible.
In this instance, the two key functions are enumerate() and max().
enumerate() converts a list (or actually any iterable) into a sequence of indices and values. e.g.
>>> list1 = ['apple', 'banana', 'cherry']
>>> for tup in enumerate(list1):
... print tup
...
(0, 'apple')
(1, 'banana')
(2, 'cherry')
max() takes an iterable and returns the maximum element. Unfortunately, max(enumerate(list1)) doesn't work, because max() will sort based on the first element of the tuple created by enumerate(), which sadly is the index.
One lesser-known feature of max() is that it can take a second argument in the form max(list1, key=something). The key is a function that can be applied to each value in the list, and the output of that function is what gets used to determine the maximum. We can use this feature to tell max() that it should be ranking items by the second item of each tuple, which is the value contained in the list.
Combining enumerate() and max() with key (plus a little help from lambda to create a function that returns the second element of a tuple) gives you this solution.
index, value = max(enumerate(list1), key=lambda x: x[1])
I came up with this recently (and am sprinkling it everywhere in my code) after watching Raymond Hettinger's talk on Transforming Code into Beautiful, Idiomatic Python, where he suggests exorcising the for i in xrange(len(list1)): pattern from your code.
Alternatively, without resorting to lambda (Thanks #sweeneyrod!):
from operator import itemgetter
index, value = max(enumerate(list1), key=itemgetter(1))
I believe if you change your for loop to....
for i in range (len(arg)):
if arg[i] > ans:
ans = arg[i]
it should work.
You could try something like this. If the list is empty, then the function will return an error.
m is set to the first element of the list, we then iterate over the list comparing the value at ever step.
def findMax(xs):
m = xs[0]
for x in xs:
if x > m:
m = x
return m
findMax([]) # error
findMax([1]) # 1
findMax([2,1]) # 2
if you wanted to use a for loop and make it more generic, then:
def findGeneric(pred, xs):
m = xs[0]
for x in xs:
if pred(x,m):
m = x
return m
findGeneric(lambda a,b: len(a) > len(b), [[1],[1,1,1,1],[1,1]]) # [1,1,1,1]

Categories