Given the following list:
x =[None, None, 1, 2, None, None, 3, 4, None, 5, None, None]
The question asks us to replace None values with the previous value.
When I run both these solutions in Google Colab, they result in the identical answer:
x =[None, None, 1, 2, None, None, 3, 4, None, 5, None, None]
def replace(x):
for i,v in enumerate(x):
if x[i] is None:
x[i]=x[i-1]
return x
y =[None, None, 1, 2, None, None, 3, 4, None, 5, None, None]
def replace(y):
for i,v in enumerate(y[:-1],1):
if y[i] is None:
y[i]=y[i-1]
return y
Both return the following:
[None, None, 1, 2, 2, 2, 3, 4, 4, 5, 5, 5]
I'm trying to understand why these solutions are equivalent. Additionally, given the equivalence, what is the rationale for the y[:-1] in the enumerate statement?
Thank you.
They are not completely equivalent. The first solution will use the last item in the list to replace the None value at index 0. The second solution does not replace the item at index zero (given that it has no predecessor). So, depending on the wording of the problem statement, one of the solutions is probably wrong.
enumerate has two parameters, an iterable and a start.
When you write enumerate( y[:-1], 1 ) two things happen:
You are giving a chopped of copy of the y array to the for loop ( you chopped of the last element of the array ), but in your for loop, you actually working on the real y array, which is not chopped of.
If you set your y to y = y[:-1] before the for loop and give that to the enumerate ( enumerate( y, 1 ) ) you will see a list is out of index error.
When you give the enumerate a 1 as a starting number, you are actually skipping the first element of your real y array (array index starts at 0, and you are starting with a y[1] in your for loop). Because of that ( and because of the 1. point ) you will reach the last element of the real y array.
enumerate accepts an optional argument that allows us to specify the starting index of the counter. So when you do :
enumerate(y[:-1],1)
instead of :
enumerate(y)
you are just shift your index:
0 None
1 None
2 1
3 2
4 None
...
vs
1 None
2 None
3 1
4 2
5 None
...
And to conclude, given that your input is a list, and that you add an index using enumerate, BUT your output is a list without any index, obviously you cannot see any difference.
In python when you have a list x and you do x[:-1] you are creating a new list without the last element. You ask for a rationale but I really cannot see how adding this would help in any way.
The fact that you start the enumerate on 1 in the second example can give you some weird behaviour
If you try the following list:
x = [None, None, 1, 2, None, None, 3, 4, None, 5, None, 6]
You will get the next two results:
[6, 6, 1, 2, 2, 2, 3, 4, 4, 5, 5, 6]
[None, None, 1, 2, 2, 2, 3, 4, 4, 5, 5, 6]
This happens since the enumerate starts on 1 so you ignore y[0] = y[-1]
Related
I'm doing this test on testdome.com for practicing , and it's failing some test case. Can anyone help me pointing out the logic error in my code?
This is the question for my code:
"Write a function that, when passed a list and a target sum, returns, efficiently with respect to time used, two distinct zero-based indices of any two of the numbers, whose sum is equal to the target sum.
If there are no two numbers, the function should return None.
For example, find_two_sum([3, 1, 5, 7, 5, 9], 10) should return a single tuple containing any of the following pairs of indices:
0 and 3 (or 3 and 0) because addition of 3 and 7 is 10.
1 and 5 (or 5 and 1) because addition of 1 and 9 is 10.
2 and 4 (or 4 and 2) because addition of 5 and 5 is 10.
def find_two_sum(numbers, target_sum):
sss=list(dict.fromkeys(numbers))
if (sss == None or len(sss) < 2): return None
for item in sss:
tesn=target_sum-item
if tesn in sss:
if numbers.index(item)==numbers.index(tesn):
continue
else:
return numbers.index(item),numbers.index(tesn)
return None
print(find_two_sum([3, 1, 5, 7, 5, 9], 10))
They have four test cases and my code can only pass first two test cases.
Example case:Wrong answer ( to return [0,2] because 3 of index 0 + 7 of index 3 is 10)
Distinct numbers with and without solutions: Wrong answer
Duplicate numbers with and without solutions: Wrong answer
Performance test with a large list of numbers: Wrong answer
My take on the problem:
def find_two_sum(lst, n):
indices = {}
for idx, num in enumerate(lst):
indices.setdefault(num, []).append(idx)
for k, v in indices.items():
i = v.pop()
if n - k in indices and indices[n-k]:
return i, indices[n-k].pop()
print( find_two_sum([3, 1, 5, 7, 5, 9], 6) )
print( find_two_sum([3, 1, 5, 7, 5, 9], 10) )
print( find_two_sum([1, 2, 1, 8], 10) )
print( find_two_sum([5, 5], 10) )
print( find_two_sum([11], 10) )
Prints:
(1, 4)
(0, 3)
(1, 3)
(1, 0)
None
I believe you have to add a check for the two indexes to be distinct.
For example here:
print(find_two_sum([3, 1, 5, 7, 5, 9], 6))
The function will give an answer of (0, 0) which wouldn't be correct, though these are the indexes of 3, which gives a sum of 6 with itself .
Here, I've added the check for distinct indexes:
def find_two_sum(numbers, target_sum):
sss = list(dict.fromkeys(numbers))
if (sss == None or len(sss) < 2): return None
tup=()
for item in sss:
item_index = numbers.index(item)
tesn = target_sum - item
if tesn in sss:
tesn_index = numbers.index(tesn)
if item_index!=tesn_index:
return (item_index, tesn_index)
return None
One flaw in the logic is that sss does not contain duplicates that may exist in the original list - you have lost information. You are assuming there are no duplicates in the original list: list.index(n) will return the index of the first item equal to n so you can end up with a result with duplicate indices
>>> a = [3, 1, 5, 7, 5, 9]
>>> item = 5
>>> tesn = 5
>>> a.index(item),a.index(tesn)
(2, 2)
>>>
Your algorithm has a flaw e.g. find_two_sum([5, 2], 10) gives (0, 0).
This is because when you check item in sss, it's gonna evaluate to true when item is 5, there is only a single 5 in the input list.
This answer seems to be 50% correct.
def find_two_sum(numbers, target_sum):
for n in numbers:
for i in numbers[numbers.index(n)+1:]:
if n+i==target_sum:
return(numbers.index(n),numbers.index(i))
break
return None
print(find_two_sum([3, 1, 5, 7, 5, 9], 10))
I would like to know how to transfer a number.
For example: [1,0,2,3,4]
Remove the one and transfer the one to two's position
Result: [0,0,1,3,4]
If your manipulations are purely index-based, you can do this:
lst = [1,0,2,3,4]
lst[2] = lst[0]
lst[0] = 0
# [0, 0, 1, 3, 4]
Alternatively, if you need to work out the index of 2:
lst[lst.index(2)] = lst[0]
lst[0] = 0
Since you have not described your question with clear instructions, There is case when there will be more than one 2 or 1 in vector then what you want to do ?
My solution is only for that condition when there is single 1 and 2 in vector because when you use .index method it always returns first value index no matter there are other values too.
Since in your dataset there is always 1 times 1 and 2 in all vector so here is the solution for that
data=[[1, 2, 3, 4, 0], [1, 3, 2, 4, 0], [2, 1, 3, 4, 0] ]
def replace_ (vector_ , replace_value, replace_with):
memory=vector_.index(replace_with)
vector_[vector_.index(replace_value)]=vector_[vector_.index(replace_with)]
vector_[memory]=0
return vector_
for i in data:
print(replace_(i,1,2))
If there are more than one 1 or 2 in vector like [1,0,1,1,2,2] then describe your logic and edit your question for that.
I hope anyone can help me with the following. I have a list called: 'List'. And I have a list called X.
Now I would like to check whether the value in the third column of each row in List is smaller than (<) X or equal/bigger than X. If the value is smaller I would like to add a 0 to the 6th column and a 1 if it is equal/bigger. And for each X I would like the answers to be added to the upfollowing columns to List. So in this case there are 4 X values. So as a result 4 columns should be added to List. My code below probably shows I'm quite an amature and I hope you can help me out. Thank you in advance.
List = [(3,5,6,7,6),(3,5,3,2,6),(3,6,1,0,5)]
X= [1,4,5,6]
for item in X:
for number in row[3] for row in List:
count = 0
if number < item:
List[5+count].append(0)
count += 1
return List
else:
List[5+count].append(1)
count += 1
return List
return List
First, you should know that tuples (parenthesis enclosed lists) are immutable, so you can not change anything about them once they're defined. It's better to use a list in your case (enclosed by []).
List = [[3,5,6,7,6],[3,5,3,2,6],[3,6,1,0,5]]
X= [1,4,5,6]
for item in X: # loop on elements of X
for subList in List: # loop on 'rows' in List
if subList[2] < item: # test if 3rd element is smaller than item in X
subList.append(0); # push 0 to the end of the row
else:
subList.append(1); # push 1 to the end of the row
List = [(3,5,6,7,6),(3,5,3,2,6),(3,6,1,0,5)]
X= [1,4,5,6]
scores = []
for item in List:
scores.append(tuple(map(lambda x: 0 if item[2] < x else 1, X)))
result = []
for item, score in zip(List, scores):
result.append(item + score)
print(result)
# [(3, 5, 6, 7, 6, 1, 1, 1, 1), (3, 5, 3, 2, 6, 1, 0, 0, 0), (3, 6, 1, 0, 5, 1, 0, 0, 0)]
Your indentation is off (you should unindent everything starting with your for statement.
You can't append to tuples (your rows inside the List variable are actually tuples).
Since you are not in a function, return does not do anything.
Since indices start with 0, you should use row[2] for 3rd row.
There are more elements in your X than the number of rows in List.
That being said, you can also use list comprehensions to implement this. Here is a one-liner that does the same thing:
>>> List = [(3,5,6,7,6),(3,5,3,2,6),(3,6,1,0,5)]
>>> X = [1,4,5,6]
>>> print [tuple(list(t[0])+[0]) if t[0][2] < t[1] else tuple(list(t[0]) + [1]) for t in zip(List, X)]
will print
[(3, 5, 6, 7, 6, 1), (3, 5, 3, 2, 6, 0), (3, 6, 1, 0, 5, 0)]
List = [[3,5,6,7,6],[3,5,3,2,6],[3,6,1,0,5]]
X= [1,4,5,6]
elems = [row[3] for row in List]
for i in range(len(elems)):
for x in X:
if elems[i] < x:
List[i].append(0)
else:
List[i].append(1)
print List
And you cannot use return if you are not using functions.
return needs to be called from inside a function. It exits the function and the value specified by return is given back to the function.
So you can't use it in your program.
In the list, each row is actually known as a tuple. Tuples don't have the append function so you can't use that to add to the end of a row.
Also, you can't have two for loops in a single line. (Which is not a problem since we only need one to achieve your output)
I've modified your code so that it looks similar so it's easier for you to understand.
List = [(3,5,6,7,6),(3,5,3,2,6),(3,6,1,0,5)]
X= [1,4,5,6]
for item in X:
n = 0
for row in list:
if row[3] < item:
list[n] = list[n] + (0,)
else:
list[n] = list[n] + (1,)
n = n+1
print List
You need to add with (0,) or (1,) to show that it's a tuple addition. (Or else python will think that you're adding a tuple with an integer)
agree with Selcuk
[edited #1: Thanks #Rawing, I mistyped > as <]
Here is AlmostGr's version simplified:-
List = [[3, 5, 6, 7, 6], [3, 5, 3, 2, 6], [3, 6, 1, 0, 5]]
X = [1, 4, 5, 6]
for num in X:
for item in List:
if num > item[2]:
item.append(0)
else:
item.append(1)
it runs for all elements in X and produces the output:
[[3, 5, 6, 7, 6, 1, 1, 1, 1], [3, 5, 3, 2, 6, 1, 0, 0, 0], [3, 6, 1, 0, 5, 1, 0, 0, 0]]
I have the following Python dict:
[(2, [3, 4, 5]), (3, [1, 0, 0, 0, 1]), (4, [-1]), (10, [1, 2, 3])]
Now I want to sort them on the basis of sum of values of the values of dictionary, so for the first key the sum of values is 3+4+5=12.
I have written the following code that does the job:
def myComparator(a,b):
print "Values(a,b): ",(a,b)
sum_a=sum(a[1])
sum_b=sum(b[1])
print sum_a,sum_b
print "Comparision Returns:",cmp(sum_a,sum_b)
return cmp(sum_a,sum_b)
items.sort(myComparator)
print items
This is what the output that I get after running above:
Values(a,b): ((3, [1, 0, 0, 0, 1]), (2, [3, 4, 5]))
2 12
Comparision Returns: -1
Values(a,b): ((4, [-1]), (3, [1, 0, 0, 0, 1]))
-1 2
Comparision Returns: -1
Values(a,b): ((10, [1, 2, 3]), (4, [-1]))
6 -1
Comparision Returns: 1
Values(a,b): ((10, [1, 2, 3]), (3, [1, 0, 0, 0, 1]))
6 2
Comparision Returns: 1
Values(a,b): ((10, [1, 2, 3]), (2, [3, 4, 5]))
6 12
Comparision Returns: -1
[(4, [-1]), (3, [1, 0, 0, 0, 1]), (10, [1, 2, 3]), (2, [3, 4, 5])]
Now I am unable to understand as to how the comparator is working, which two values are being passed and how many such comparisons would happen? Is it creating a sorted list of keys internally where it keeps track of each comparison made? Also the behavior seems to be very random. I am confused, any help would be appreciated.
The number and which comparisons are done is not documented and in fact, it can freely change from different implementations. The only guarantee is that if the comparison function makes sense the method will sort the list.
CPython uses the Timsort algorithm to sort lists, so what you see is the order in which that algorithm is performing the comparisons (if I'm not mistaken for very short lists Timsort just uses insertion sort)
Python is not keeping track of "keys". It just calls your comparison function every time a comparison is made. So your function can be called many more than len(items) times.
If you want to use keys you should use the key argument. In fact you could do:
items.sort(key=lambda x: sum(x[1]))
This will create the keys and then sort using the usual comparison operator on the keys. This is guaranteed to call the function passed by key only len(items) times.
Given that your list is:
[a,b,c,d]
The sequence of comparisons you are seeing is:
b < a # -1 true --> [b, a, c, d]
c < b # -1 true --> [c, b, a, d]
d < c # 1 false
d < b # 1 false
d < a # -1 true --> [c, b, d, a]
how the comparator is working
This is well documented:
Compare the two objects x and y and return an integer according to the outcome. The return value is negative if x < y, zero if x == y and strictly positive if x > y.
Instead of calling the cmp function you could have written:
sum_a=sum(a[1])
sum_b=sum(b[1])
if sum_a < sum_b:
return -1
elif sum_a == sum_b:
return 0
else:
return 1
which two values are being passed
From your print statements you can see the two values that are passed. Let's look at the first iteration:
((3, [1, 0, 0, 0, 1]), (2, [3, 4, 5]))
What you are printing here is a tuple (a, b), so the actual values passed into your comparison functions are
a = (3, [1, 0, 0, 0, 1])
b = (2, [3, 4, 5]))
By means of your function, you then compare the sum of the two lists in each tuple, which you denote sum_a and sum_b in your code.
and how many such comparisons would happen?
I guess what you are really asking: How does the sort work, by just calling a single function?
The short answer is: it uses the Timsort algorithm, and it calls the comparison function O(n * log n) times (note that the actual number of calls is c * n * log n, where c > 0).
To understand what is happening, picture yourself sorting a list of values, say v = [4,2,6,3]. If you go about this systematically, you might do this:
start at the first value, at index i = 0
compare v[i] with v[i+1]
If v[i+1] < v[i], swap them
increase i, repeat from 2 until i == len(v) - 2
start at 1 until no further swaps occurred
So you get, i =
0: 2 < 4 => [2, 4, 6, 3] (swap)
1: 6 < 4 => [2, 4, 6, 3] (no swap)
2: 3 < 6 => [2, 4, 3, 6] (swap)
Start again:
0: 4 < 2 => [2, 4, 3, 6] (no swap)
1: 3 < 4 => [2, 3, 4, 6] (swap)
2: 6 < 4 => [2, 3, 4, 6] (no swap)
Start again - there will be no further swaps, so stop. Your list is sorted. In this example we have run through the list 3 times, and there were 3 * 3 = 9 comparisons.
Obviously this is not very efficient -- the sort() method only calls your comparator function 5 times. The reason is that it employs a more efficient sort algorithm than the simple one explained above.
Also the behavior seems to be very random.
Note that the sequence of values passed to your comparator function is not, in general, defined. However, the sort function does all the necessary comparisons between any two values of the iterable it receives.
Is it creating a sorted list of keys internally where it keeps track of each comparison made?
No, it is not keeping a list of keys internally. Rather the sorting algorithm essentially iterates over the list you give it. In fact it builds subsets of lists to avoid doing too many comparisons - there is a nice visualization of how the sorting algorithm works at Visualising Sorting Algorithms: Python's timsort by Aldo Cortesi
Basically, for the simple list such as [2, 4, 6, 3, 1] and the complex list you provided, the sorting algorithms are the same.
The only differences are the complexity of elements in the list and the comparing scheme that how to compare any tow elements (e.g. myComparator you provided).
There is a good description for Python Sorting: https://wiki.python.org/moin/HowTo/Sorting
First, the cmp() function:
cmp(...)
cmp(x, y) -> integer
Return negative if x<y, zero if x==y, positive if x>y.
You are using this line: items.sort(myComparator) which is equivalent to saying: items.sort(-1) or items.sort(0) or items.sort(1)
Since you want to sort based on the sum of each tuples list, you could do this:
mylist = [(2, [3, 4, 5]), (3, [1, 0, 0, 0, 1]), (4, [-1]), (10, [1, 2, 3])]
sorted(mylist, key=lambda pair: sum(pair[1]))
What this is doing is, I think, exactly what you wanted. Sorting mylist based on the sum() of each tuples list
I made a function with a dictionary. The purpose of the function is to separate the input string into sets of 3 . If the input string value is not a multiple of 3, I want to delete the remainder [1 or 2]
my function was working perfectly until I added the part for deleting the remainders
def func(fx):
d={'AAA':1,'BBB':2,'CCC':3}
length=len(fx)
if length % 3 == 0:
return fx
if length % 3 == 1:
return fx[:-1]
if length % 3 == 2:
return fx[:-2]
Fx=fx.upper()
Fx3=[Fx[i:i+3] for i in range(0,len(Fx),3)]
translate=[d[x] for x in Fx3]
return translate
x='aaabbbcc'
output = func(x)
print output
>>>
aaabbb
the function is recognizing that the input sequence is not a multiple of 3 so its deleting the 2 values which is what i want. However, its splitting the new string into 3 letter words to be translated with my dictionary anymore. If you delete the if statements, the function works but only for strings that are a multiple of 3.
What am I doing wrong ???
You are returning fx when you probably should be reassigning it
def func(fx):
d={'AAA':1,'BBB':2,'CCC':3}
length=len(fx)
if length % 3 == 0:
pass
elif length % 3 == 1:
fx = fx[:-1]
elif length % 3 == 2:
fx = fx[:-2]
Fx=fx.upper()
Fx3=[Fx[i:i+3] for i in range(0,len(Fx),3)]
translate=[d[x] for x in Fx3]
return translate
Here is an alternate function for you to figure out when you know some more Python
def func(fx):
d = {'AAA':1,'BBB':2,'CCC':3}
return [d["".join(x).upper()] for x in zip(*[iter(fx)]*3)]
Does this do what you want?
def func(fx):
d = {'AAA': 1, 'BBB': 2, 'CCC': 3}
fx = fx[:-(len(fx)%3)].upper()
groups = [fx[i:i+3] for i in range(0, len(fx), 3)]
translate = [d[group] for group in groups]
return translate
x='aaabbbcc'
print func(x)
When trimming the end of the string, you were returning the result when you wanted to just store it in a variable or assign it back to fx.
Rather than the if .. elifs you can just use the result of the length modulo 3 directly.
There is no need of a function, it can be done in a one liner less complex than the gnibbler's one.
Acom's solution is nearly mine.
d={'AAA':1,'BBB':2,'CCC':3}
for fx in ('bbbcccaaabbbcccbbbcccaaabbbcc',
'bbbcccaaabbbaaa','bbbcccaaabbbaa','bbbcccaaabbba',
'bbbcccaaabbb','bbbcccaaabb','bbbcccaaab',
'bbbcccaaa','bbbcccaa','bbbccca',
'bbbccc','bbbcc','bbbc',
'bbb','bb','b',''):
print fx
print tuple( d[fx[i:i+3].upper()] for i in xrange(0, len(fx)-len(fx)%3, 3) )
produces
bbbcccaaabbbcccbbbcccaaabbbcc
(2, 3, 1, 2, 3, 2, 3, 1, 2)
bbbcccaaabbbaaa
(2, 3, 1, 2, 1)
bbbcccaaabbbaa
(2, 3, 1, 2)
bbbcccaaabbba
(2, 3, 1, 2)
bbbcccaaabbb
(2, 3, 1, 2)
bbbcccaaabb
(2, 3, 1)
bbbcccaaab
(2, 3, 1)
bbbcccaaa
(2, 3, 1)
bbbcccaa
(2, 3)
bbbccca
(2, 3)
bbbccc
(2, 3)
bbbcc
(2,)
bbbc
(2,)
bbb
(2,)
bb
()
b
()
()
.
I think you have to treat strings that can contain only 3 characters strings 'aaa','bbb','ccc' at the positions 0,3,6,9,etc
Then the preceding programs won't crash if there's an heterogenous 3-characters string at one of these positions instead of one of these set 'aaa','bbb','ccc'
In this case, note that you could use the dictionary's method get that returns a default value when a pased argument isn't a key of the dictionary.
In the following code, I put the default returned value as 0:
d={'AAA':1,'BBB':2,'CCC':3}
for fx in ('bbbcccaaa###bbbccc"""bbbcc',
'bbb aaabbbaaa','bbbccc^^^bbbaa','bbbc;;;aabbba',
'bbbc^caaabbb',']]bccca..bb','bbb%%%aaab',
'bbbcccaaa','bbb!ccaa','b#bccca',
'bbbccc','bbbcc','bbbc',
'b&b','bb','b',''):
print fx
print [d.get(fx[i:i+3].upper(), 0) for i in xrange(0, len(fx)-len(fx)%3, 3)]
produces
bbbcccaaa###bbbccc"""bbbcc
[2, 3, 1, 0, 2, 3, 0, 2]
bbb aaabbbaaa
[2, 0, 1, 2, 1]
bbbccc^^^bbbaa
[2, 3, 0, 2]
bbbc;;;aabbba
[2, 0, 0, 2]
bbbc^caaabbb
[2, 0, 1, 2]
]]bccca..bb
[0, 3, 0]
bbb%%%aaab
[2, 0, 1]
bbbcccaaa
[2, 3, 1]
bbb!ccaa
[2, 0]
b#bccca
[0, 3]
bbbccc
[2, 3]
bbbcc
[2]
bbbc
[2]
b&b
[0]
bb
[]
b
[]
[]
By the way, I preferred to create a tuple instead of a list because for the kind of invariable objects that are in the result, I think it is better not to create a list