Unexpected output after merging two sorted arrays with Python - python

I found a partial solution to the problem; however, it seems that I'm getting extra numbers from my array than what it should be. This is the question I'm trying to find out:
Given two sorted integer arrays nums1 and nums2, merge nums2 into
nums1 as one sorted array.
Note:
The number of elements initialized in nums1 and nums2 are m and n
respectively. You may assume that nums1 has enough space (size that is
greater or equal to m + n) to hold additional elements from nums2.
Example:
Input: nums1 = [1,2,3,0,0,0], m = 3 nums2 = [2,5,6], n = 3
Output: [1,2,2,3,5,6]
I'm practicing some coding challenges to the hang of Python3 language and prepare myself for an interview. I have tried a few methods like using pop when the beginning of the array are 0s. But it seems that after new test case showed up, I should've expected more. I'm pretty new with the language.
def mergeArrays(nums1, m, nums2, n):
nums1[:] = sorted(nums1 + nums2)
i = 0
while (i < len(nums1[:-1])):
if nums1[i] is 0:
nums1.pop(i)
if i > len(nums1):
break
i += 1
print(nums1)
nums1 = [-49,-48,-48,-47,-45,-42,-39,-36,-33,-33,-28,-28,-23,-23,-7,-4,-3,0,0,4,6,21,29,29,31,34,36,38,40,43,45,46,47,0,0,0,0,0,0,0,0]
m = len(nums1)
nums2 = [-16,-5,-3,26,33,35,38,41]
n = len(nums2)
mergeArrays(nums1, m, nums2, n);
My expected output should be of both arrays sorted and go through. Results should be this: [-49,-48,-48,-47,-45,-42,-39,-36,-33,-33,-28,-28,-23,-23,-16,-7,-5,-4,-3,-3,0,0,4,6,21,26,29,29,31,33,34,35,36,38,38,40,41,43,45,46,47]
However, I'm getting a couple extra zeros, which should look like this:
[-49,-48,-48,-47,-45,-42,-39,-36,-33,-33,-28,-28,-23,-23,-16,-7,-5,-4,-3,-3,0,0,0,0,0,4,6,21,26,29,29,31,33,34,35,36,38,38,40,41,43,45,46,47]
EDIT: added more information to make the problem clear.

As per my understanding you want to sort the two sorted array without having any duplicate element. You can refer the below code:
first_list = [-49,-48,-48,-47,-45,-42,-39,-36,-33,-33,-28,-28,-23,-23,-7,-4,-3,0,0,4,6,21,29,29,31,34,36,38,40,43,45,46,47,0,0,0,0,0,0,0,0]
second_list = [-16,-5,-3,26,33,35,38,41]
merged_list = list(set(first_list+second_list))
merged_list.sort()
print(merged_list)

With one of the old methods that I used was a loop comprehension. Basically, what I did was array splice from beginning to end and do the sort inside of the loop:
def mergeArrays(nums1, m, nums2, n):
nums1[0: m + n] = [x for x in sorted(nums1[:m] + nums2[:n])]
If you have a different explanation than what I just did, please feel free :)

After much back-and-forth on the intent of your code and where your unwanted mystery zeros come from, seems you want to do the following: merge-sort your two arrays, preserving duplicates:
your input is arrays nums1, nums2 which are zero-padded, and can be longer than length m,n respectively
But to avoid picking up those padded zeros, you should only reference the entries 0..(m-1), i.e. nums1[:m], and likewise nums2[:n]
Your mistake was to reference all the way up to nums1[:-1]
Your solution is: sorted(nums1[:m] + nums2[:n]). It's a one-liner list comprehension and you don't need a function.
There is no reason whatsoever that zero entries need special treatment. There's no need for your while-loop.
Also btw even if you wanted to (say) exclude all zeros, you can still use a one-liner list-comprehension: x for x in sorted(nums1[:m] + nums2[:n]) if x != 0]
List comprehensions are a neat idiom and super-powerful! Please read more about them. Often you don't need while-loops in Python; list comprehensions, iterators or generators are typically cleaner, shorter code and more efficient.

Related

Why does it not remove all zeroes from the list

I haven't coded in Python for a long time and sometimes I'm quite confused.
When I have an array, like eg.: arr = [0, 1, 0, 3, 12]
and say:
for i in arr:
if i == 0:
arr.remove(i)
it is removing the two zeroes the way I want.
But if the array is something like: arr = [0, 0, 1], with the above method, one 0 will remain.
So could someone explain me why the behavior is like that? I don't find an explanation for this.
Better try this:
arr = [n for n in arr if n != 0]
This uses a list comprehension, it's a lot safer than what you're doing: removing the elements at the same time you're iterating is a bad idea, and you'll experience problems such as elements not being removed.
This is because the list size is reduced and the iterator traversing it will find less elements than it was expecting when the iteration began.
I think I found why your method doesn't work. The problem comes from the way you iterate.
In your example, your function seems to work for arr = [0,1,0,3,12] but not on your second array arr2 = [0,0,2] and returns [0,2]. One interesting thing to investigate then, is the fact that in your second example, you have two consecutive zeros.
Take a look at this code and try to execute it :
for i in arr:
print('i = '+str(i))
if(i == 0):
arr.remove(i)
With your first array, you noticed that your output is the one you expected but that was lucky. As a matter of fact, if you run the code above, you would see that it prints in your console :
> i = 0
> i = 0
> i = 12
So, actually, this means that your remove statement changes the array you iterate on. After a deletion, you skip an element in your array.
This means you should prefer another way, like the ones suggested in comments.
Hope this helps
you can filter out your zeros with the built-in function filter:
arr = list(filter(None, arr))
you have to pay attention if you use filter function with None as first parameter, this will apply bool over your items if you have elements like None, 0 or the empty string '' the result will be the same, False and all these elements will be filtered out, for safety reasons you may use:
arr = list(filter(lambda x: x != 0 , arr))

Does Python syntax prevent me from creating this list comprehension?

I am trying to recreate a for loop (A) into a list comprehension. I think the problem here is that there are too many functions that need to be done to ni, namely squaring it and then making sure it is an integer before appending onto nn .
The list comprehension (B) is an attempt at getting the list comprehension to take a string (m) and square each individual number as an integer. The problem is that it needs to iterate over each number as a string THEN square itself as individual integers.
A
n = str(2002)
nn = []
for x in range(len(n)):
ni = n[x]
ns = int(ni)**2
nn.append(ns)
print(nn)
[4, 0, 0, 4]
B
m = str(9119)
mm = [(int(m[x]))**2 for x in m]
TypeError: string indices must be integers
This makes me feel like A cannot be done as a list comprehension? Love to see what your thoughts for alternatives and/or straight up solutions are.
You are passing a string as the index!
Additionally, you were trying to index the string m with the number at each index instead of its index (e.g, you tried to index m[0] with m[9] instead)
Try using the following instead:
m = str(9119)
mm = [int(x)**2 for x in m] #Thanks #Gelineau
Hope this helps!
x represents each digit in m. So you just have to square it
mm = [int(x)**2 for x in m]

To find the minimum(least) number of Unique numbers in a given list after 'n' reductions

Problem Statement: To find the minimum(least) number of Unique numbers in a given list after 'n' reductions
Input:
N and an Array(or list)
Where 0 < N < len(Array)
N is the number of reductions possible and the input for the array needs to be separated by commas(,)
Example 1:
N = 2
Array = 1, 2, 3, 3, 4, 4
Output:
To find the Least or minimum number of unique elements after deleting N number of elements in the Array
In the above example,
After deleting N = 2 number of elements from the Array
In the above example 1, 2 should be deleted from the array
3, 3, 4, 4 will be remaining
So, 2 unique elements remaining after deleting 2 elements from the array
So, the output should be 2
Example 2:
N = 2 [ number of reductions possible]
Input Array : 1,3,4,1,2,4,2,2
Output: 3 [least number of unique elements]
Explanation :[1,1,2,2,4,4] will be the resultant array when [2,3] are removed
Supposed to be coded in Python exclusively but solutions in any language will be appreciated.
Finding the minimum number of unique elements is equivalent to finding the maximum number of duplicates.
The driving idea here would be to use your reductions to take out the elements that appear the fewest number of times first. In order to do that, you'd want to count the number of occurrences of each element in the list, sort them by number of occurrences, and remove them from least to most until you run out of deletions. The only tricky part is the first part, and that's only if you have to code it in pure python (#DerekLangley's answer gives a good example of how you might do that).
If you're allowed to import other parts of the standard library, then collections.Counter makes quick work of this problem. Here's a sample implementation that doesn't account for anything that could go wrong (such as an empty list, or N being larger than len(lst) - these are things that the interviewer would expect you to mention and know how to handle, so work on that).
import collections
...
def min_uniques(N, lst):
# use collections.Counter to get a sorted list of unique elements and their frequencies
most_common = collections.Counter(lst).most_common()
# returns [(most_frequent, num_occurrences), ...], so we pull from the back to get fewest occurrences.
# We could reverse the list and pull from the front but that would be less efficient
while N >= most_common[-1][1]:
# remove the element with lowest count and subtract its count from N, all at once
N -= most_common.pop()[1]
# return the number of unique elements left, after we can no longer remove enough to decrease that count
return len(most_common)
min_uniques(2, [1, 2, 3, 3, 4, 4])
# 2
min_uniques(2, [1, 3, 4, 1, 2, 4, 2, 2])
# 3
My comments on that code represent how I would talk through the problem with the interviewer as I was writing it. This is a four-line python function, but I'm pretty sure you could also do it in two - the interviewer might ask for how you can improve this code, and if you can put in that as an example (maybe say "I think it would use mechanism X or mechanism Y, but I'd have to look at the documentation and do some tinkering first).
I don't especially see how Dynamic Programming is relevant here, though I kind of feel like Dynamic Programming is a bit of a buzzword anyway.
Since you do not show any code of your own, I will just give some ideas for an algorithm. If you want more details, please show some of your own code.
The Counter object in the collections module in Python's standard library can count the number of occurrences of each number in the array. Use Counter to do that for your array. The size of the resulting Counter object is the number of unique items in the array.
Then use Counter's most_common method to sort that information from the most popular number to the least popular. Now look at that result from the least popular end. Use your value of N to "remove" the least popular values in the array. You don't need to actually do the removal--just do it conceptually. When you have done that removal (conceptually or actually), the size of the Counter object is then your answer.
Of course, there are ways to do this without Counter but the code will be more lengthy. Again, show some more effort of your own then I will be glad to give more details.
Here's a (probably) inefficient way of doing it.
ls = [1,3,4,1,2,4,2,2]
d = {}
for i in ls:
if i not in d:
d[i] = 1
else:
d[i] += 1
def min_num(n):
counter = n
while counter > 0:
del d[min(d, key = d.get)]
counter -= 1
return len(d.keys())
min_num(2)

Iterating efficiently through indices of arbitrary order array

Say I have an arbitrary array of variable order N. For example:
A is a 2x3x3 array is an order 3 array with 2,3, and 3 dimiensions along it's three indices.
I would like to efficiently loop through each element. If I knew a priori the order then I could do something like (in python),
#for order 3
import numpy as np
shape = np.shape(A)
i = 0
while i < shape[0]:
j = 0
while j < shape[1]:
k = 0
while k < shape[2]:
#code using i,j,k
k += 1
j += 1
i += 1
Now suppose I don't know the order of A, i.e. I don't know a priori the length of shape. How can I permute the quickest through all elements of the array?
There are many ways to do this, e.g. iterating over a.ravel() or a.flat. However, looping over every single element of an array in a Python loop will never be particularly efficient.
I don't think it matters which index you choose to permute over first, which index you choose to permute over second, etc. because your inner-most while statement will always be executed once per combination of i, j, and k.
If you need to keep the results of your operation (and assuming its a function of A and i,j,k) You'd want to use something like this:
import itertools
import numpy as np
results = ( (position, code(A,position))
for indices in itertools.product(*(range(i) for i in np.shape(A))))
Then you can iterate the results getting out the position and return value of code for each position. Or convert the generator expression to a list if you need to access the results multiple times.
If the array of of the format array = [[[1,2,3,4],[1,2]],[[1],[1,2,3]]]
You could use the following structure:
array = [[[1,2,3,4],[1,2]],[[1],[1,2,3]]]
indices = []
def iter_array(array,indices):
indices.append(0)
for a in array:
if isinstance(a[0],list):
iter_array(a,indices)
else:
indices.append(0)
for nonlist in a:
#do something using each element in indices
#print(indices)
indices.append(indices.pop()+1)
indices.pop()
indices.append(indices.pop()+1)
indices.pop()
iter_array(array,indices)
This should work for the usual nested list "arrays" I don't know if it would be possible to mimic this using numpy's array structure.

How is this 2D array being sized by FOR loops?

Question background:
This is the first piece of Python code I've looked at and as such I'm assuming that my thread title is correct in explaining what this code is actually trying to achieve i.e setting a 2D array.
The code:
The code I'm looking at sets the size of a 2D array based on two for loops:
n = len(sentences)
values = [[0 for x in xrange(n)] for x in xrange(n)]
for i in range(0, n):
for j in range(0, n):
values[i][j] = self.sentences_intersection(sentences[i], sentences[j])
I could understand it if each side of the array was set with using the length property of the sentences variable, unless this is in effect what xrange is doing by using the loop size based on the length?
Any helping with explaing how the array is being set would be great.
This code is actually a bit redundant.
Firstly you need to realize that values is not an array, it is a list. A list is a dynamically sized one-dimensional structure.
The second line of the code uses a nested list comprehension to create one list of size n, each element of which is itself a list consisting of n zeros.
The second loop goes through this list of lists, and sets each element according to whatever sentences_intersection does.
The reason this is redundant is because lists don't need to be pre-allocated. Rather than doing two separate iterations, really the author should just be building up the lists with the correct values, then appending them.
This would be better:
n = len(sentences)
values = []
for i in range(0, n):
inner = []
for j in range(0, n):
inner.append(self.sentences_intersection(sentences[i], sentences[j]))
values.append(inner)
but you could actually do the whole thing in the list comprehension if you wanted:
values = [[self.sentences_intersection(sentences[i], sentences[j]) for i in xrange(n)] for j in xrange(n)]

Categories