Find a deleted number from a list - python

Considering two lists (a sequence of numbers from 1 to N (arr) and the same sequence mixed but missing one number (mixed_arr)). The goal is to find the number that was deleted.
Example:
arr = [1,2,3,4,5]
mixed_arr = [3,4,1,5]
The output should be 2.
Return 0 if no number was deleted and if there is no difference
If no number was deleted from the array and no difference with it, the function has to return 0. Note that N may be 1 or less (in the latter case, the first array will be []).
Testcases:
arr = [1,2,3,4,5,6,7,8,9]
mixed_arr = [1,9,7,4,6,2,3,8]
output = 5
arr = [1,2,3,4,5,6,7,8,9]
mixed_arr = [5,7,6,9,4,8,1,2,3]
output = 0
Here's my code:
def find_deleted_number(arr, mixed_arr):
arr.sort()
mixed_arr.sort()
for x in range(arr):
for y in range(mixed_arr):
if arr[x] != mixed_arr[y]:
return arr[x]
elif arr[x] == mixed_arr[y]:
return 0
The error I get is:
Traceback:
in <module>
in find_deleted_number
TypeError: 'list' object cannot be interpreted as an integer

Why not to use set?
>>> arr = [1,2,3,4,5,6,7,8,9]
>>> mixed_arr = [1,9,7,4,6,2,3,8]
>>> list(set(arr) - set(mixed_arr))
[5]
This general solution will handle arrays with no constraints on integers, or on the size of lists (or the size of the difference).
Edit. In your (very) specific case with positive integers, and only one missing in the other array, it's much more efficient to use the solution from comments below:
>>> abs(sum(arr) - sum(mixed_arr))
5

You could simply use symmetric_difference(), a member of set:
set(arr).symmetric_difference(mixed_arr)
See also sets.
Please note, as pointed out by DeepSpace in the comments, if it is guaranteed that both lists contain integers from 1 to N, with the exception of one missing in one of those lists, the much more efficient solution is to compute the absolute value of the difference of the sum of both lists:
abs(sum(arr) - sum(mixed_arr))
The error you're getting:
You're getting the error because of this line:
for x in range(arr): # arr is a list, not an int
You surely intended to pass the length of the array:
for x in range(len(arr)):
The same goes for the inner loop.

Your problem is that you are trying to pass an list object to the range() function. But since range() only accepts integers, Python complains. You are also making the same mistake with mixed_arr.
But there are easier ways to accomplish this. In this case, you can use set()s to find the difference between two lists:
>>> set([1,2,3,4,5]) - set([3,4,1,5])
{2}
>>>
Or this could be done using a simple list comprehension:
>>> arr = [1,2,3,4,5]
>>> mixed_arr = [3,4,1,5]
>>>
>>> [el for el in arr if el not in mixed_arr]
[2]
>>>

Related

Finding a common number from the list and placing it in another list

I have two lists that are formed through a function called factors which returns the prime factors of a number. In my task I have to return the common numbers in both the lists to a new list.
def factors(n):
i = 2
prime_factors = []
while i*i <= n:
if n%i == 0:
prime_factors=prime_factors + [i]
n //= i
else:
i += 1
if n>1:
prime_factors=prime_factors + [n]
return prime_factors
>>>factors(4)
>>>[2,2]
>>>factors(14)
>>>[2,7]
I have to find the common number and return it in a new list. I tried my code below and it gave me result list as [2,2], whereas it should only be [2]
lst=[]
for element in factors(4):
if element in factors(14):
lst=lst+[element]
This code gives me the result as [2,2]. Kindly guide me as to how I can get only [2]. Also I am NOT allowed to use methods like set, intersection, or zip or stuff from math library. another example:
lst1=[2,2,3,3,4,5,6]
lst2=[2,2,3,4,4,7,8]
common_lst=[2,2,3,4]
(Note: this was for an earlier version of the question, before they vandalized the question to say the math "library" isn't allowed and that they want to keep common duplicates. Oh well, gcd is a short one-liner we could write ourselves instead.)
>>> from math import gcd
>>> factors(gcd(4, 14))
[2]
or
>>> [*{*factors(4)} & {*factors(14)}]
[2]
(They're not quite equivalent, they solve two different interpretations of the ambiguous question. I actually suspect the first one is the desired one, as otherwise the OP might not have made the factors function produce duplicate factors in the first place.)
The Counter method from the collections library would come in handy here. Counter takes in a list and returns a dictionary of the number of 'counts' of each value in that list.
from collections import Counter
f4 = factors(4)
f14 = factors(14)
c4 = Counter(f4)
c14 = Counter(f14)
inter = c4 & c14
lst = list(inter.elements())
inter represents the intersection between the two dictionaries. list(inter.elements()) simply retrieves the elements of the dictionary as a combination of the key and value and converts the result to a list.
If i understand the question correctly, the only way to solve it is to delete the common numbers as they are found. (To do this i have iterated through the lists backwords to prevent Index errors)
lst = []
fctrs_1 = factors(4)
fctrs_2 = factors(14)
for a in range(len(fctrs_1)-1, -1, -1):
for b in range(len(fctrs_2)-1, -1, -1):
if fctrs_1[a] == fctrs_2[b]:
lst.append(fctrs_1[a])
del fctrs_1[a]
del fctrs_2[b]
break # Break to prevent errors
print(lst)# Output: [2]

Function to find number of 'ordered combinations' with no particular length of a list Python

While variants of this question have been asked numerous times on this site, I haven't found any information on how to do 'ordered combinations' with a given list.
First of all, I don't exactly know what the correct term for this function is, but I will use this list:
list = [1,2,3,4,5,6,7,8,9,10]
What I want to find is how many possible ways this list can be ordered, so that
list[0] < list[1] < list[2] ... < list[len(list)-1] (Ascending order w/o repeats )
But
list[0] + 1 doesn't have to be equal to list[1] (Doesn't matter which numbers are chosen, so long that they are in ascending order and are in the list)
And, assuming outList is a qualifying list sourced from list
len(outList) doesn't have to be to len(list) - 'Qualifying' lists do not have to be the same length of the given list, but it must not be longer.
Some examples of what would fit under these rules:
[1,4,5,9]
[2,6,7,8,9]
[1,2,4,8]
[8,10]
Some non-examples:
[1,3,2,5,10]
[1,1,10]
[5,2,8,7,9]
Numbers CANNOT repeat, and they must strictly be larger than the previous number.
How would I go about making such a function? I haven't a clue at how to approach such a problem. I tried using a for loop, but I couldn't seem to get that to work properly.
Edit: sorry this question was unclear, and if it still is, because I really don't know what term I would use. I didn't know how to phrase it correctly, so I added some more detail, and my version of the answer is down below. Clearly it is not optimized. Btw AlexanderCĂ©cile, if you look at my history, I used to do js and jQuery (not that I don't anymore, but I changed my focus), so the function follows the naming standards of js.
Second edit: All these answers are quite different from each other, which shows the beauty of coding :) - My solution is quite basic, although it does work. Do these work quicker on higher length lists, such as [1,2,3,4...100,101]?
As I understand your question, you want to know how many different lists there are with some subset of the elements as lst, kept in order. Since each subset can only exist in one order, the answer is simply the number of subsets: 2^n where n is the length of the list.
def count_subsets(lst):
return 2 ** len(lst)
For example, if the list is [1, 2, 3] then there are 2^3 = 8 ordered sublists:
[]
[1]
[2]
[3]
[1, 2]
[1, 3]
[2, 3]
[1, 2, 3]
If you want to exclude the empty list and/or the original list, you can simply do 2 ** len(lst) - 1 or max(0, 2 ** len(lst) - 2), as appropriate. The max(0, ...) handles the special case when your input list is empty.
The above handles the case like your example when the elements of the input list are all distinct. If there may be repeated elements, then the formula above overcounts. To fix it, we can use a Counter to find the number of copies of each element. If there are k copies of some element, then instead of 2 ** k combinations, we should count k + 1 sublists containing 0, 1, 2, ..., k copies.
from collections import Counter
def count_subsets(lst):
r = 1
for k in Counter(lst).values():
r *= k + 1
return r
You can do this mathematically using the formula to calculate the number of combinations.
import math
def binomial_coeff(n, k):
return math.factorial(n) // (math.factorial(k) * math.factorial(n - k))
def num_all_combinations(lst_len):
return sum(binomial_coeff(lst_len, i) for i in range(lst_len))
list1 = list(range(10))
print(num_all_combinations(len(list1))) # prints 1023
The binomial_coeff function uses the combinations formula (also known as the binomial coefficient) to get the number of combinations for a list of size n with groups of size k. We then use the num_all_combinations function to get the number of combinations for all group sizes and add them together.
You can even simplify this further using the sums of binomial coefficients identity as suggested by #kaya3. This would result in the following code:
list1 = list(range(10))
print(2**len(list1) - 1) # prints 1023
This solution is most likely unoptimized, but I somehow figured out what I wanted to do. Is there a nice way to improve this?
def orderedCombinations():
z = 0
for x in range(len(list1)):
comb = combinations(list1, x)
for i in list(comb):
z += 1
print(str(z))

Lists in Python

I noticed that you can multiply list by scalar but the behavior is weird
If I multiply:
[2,3,4] * 3
I get:
[2,3,4,2,3,4,2,3,4]
I understand the results but what it's good for? Is there any other weird operations like that?
The main purpose of this operand is for initialisation. For example, if you want to initialize a list with 20 equal numbers you can do it using a for loop:
arr=[]
for i in range(20):
arr.append(3)
An alternative way will be using this operator:
arr = [3] * 20
More weird and normal list operation on lists you can find here http://www.discoversdk.com/knowledge-base/using-lists-in-python
The operation has a use of creating arrays initialized with some value.
For example [5]*1000 means "create an array of length 1000 initialized with 5".
If you want to multiply each element by 3, use
map(lambda x: 3*x, arr)

Dealing with multi-dimensional arrays when ndims not known in advance

I am working with data from netcdf files, with multi-dimensional variables, read into numpy arrays. I need to scan all values in all dimensions (axes in numpy) and alter some values. But, I don't know in advance the dimension of any given variable. At runtime I can, of course, get the ndims and shapes of the numpy array.
How can I program a loop thru all values without knowing the number of dimensions, or shapes in advance? If I knew a variable was exactly 2 dimensions, I would do
shp=myarray.shape
for i in range(shp[0]):
for j in range(shp[1]):
do_something(myarray[i][j])
You should look into ravel, nditer and ndindex.
# For the simple case
for value in np.nditer(a):
do_something_with(value)
# This is similar to above
for value in a.ravel():
do_something_with(value)
# Or if you need the index
for idx in np.ndindex(a.shape):
a[idx] = do_something_with(a[idx])
On an unrelated note, numpy arrays are indexed a[i, j] instead of a[i][j]. In python a[i, j] is equivalent to indexing with a tuple, ie a[(i, j)].
You can use the flat property of numpy arrays, which returns a generator on all values (no matter the shape).
For instance:
>>> A = np.array([[1,2,3],[4,5,6]])
>>> for x in A.flat:
... print x
1
2
3
4
5
6
You can also set the values in the same order they're returned, e.g. like this:
>>> A.flat[:] = [x / 2 if x % 2 == 0 else x for x in A.flat]
>>> A
array([[1, 1, 3],
[2, 5, 3]])
I am not sure the order in which flat returns the elements is guaranteed in any way (as it iterates through the elements as they are in memory, so depending on your array convention you are likely to have it always being the same, unless you are really doing it on purpose, but be careful...)
And this will work for any dimension.
** -- Edit -- **
To clarify what I meant by 'order not guaranteed', the order of elements returned by flat does not change, but I think it would be unwise to count on it for things like row1 = A.flat[:N], although it will work most of the time.
This might be the easiest with recursion:
a = numpy.array(range(30)).reshape(5, 3, 2)
def recursive_do_something(array):
if len(array.shape) == 1:
for obj in array:
do_something(obj)
else:
for subarray in array:
recursive_do_something(subarray)
recursive_do_something(a)
In case you want the indices:
a = numpy.array(range(30)).reshape(5, 3, 2)
def do_something(x, indices):
print(indices, x)
def recursive_do_something(array, indices=None):
indices = indices or []
if len(array.shape) == 1:
for obj in array:
do_something(obj, indices)
else:
for i, subarray in enumerate(array):
recursive_do_something(subarray, indices + [i])
recursive_do_something(a)
Look into Python's itertools module.
Python 2: http://docs.python.org/2/library/itertools.html#itertools.product
Python 3: http://docs.python.org/3.3/library/itertools.html#itertools.product
This will allow you to do something along the lines of
for lengths in product(shp[0], shp[1], ...):
do_something(myarray[lengths[0]][lengths[1]]

Finding the sum of a nested list of ints

import math
lists = [1,[2,3],4]
total = 0
for i in range(len(lists)):
total += sum(i)
print(total)
I want it to print,
>>>10
But throws an error.
I would like it to get it to add all numbers, including the ones within the nested if.
In your program, for i in range(len(lists)) - evaluates to 3 as the lists object has 3 element. and in the loop total += sum(i) it would try to do a int + list operation, which results in an error. Hence you need to check for the type and then add the individual elements.
def list_sum(L):
total = 0
for i in L:
if isinstance(i, list):
total += list_sum(i)
else:
total += i
return total
This is #pavelanossov 's comment - does the same thing, in a more elegant way
sum(sum(i) if isinstance(i, list) else i for i in L)
You can use flatten function in the compiler.ast module to flatten the list. Then simply sum up all the elements.
>>> lists = [1,[2,3],4]
>>> from compiler.ast import flatten
>>> sum(flatten(lists))
10
EDIT: Only works with Python 2.x
numpy.hstack() function is used to stack the sequence of input arrays horizontally (i.e. column wise) to make a single array which is what we require in OP example
import numpy as np
list1 = [1,[2,3],4]
M = np.hstack(list1)
print(np.sum(M))
gives
10
[Program finished]

Categories

Resources