Related
I have a question: Starting with a 1-indexed array of zeros and a list of operations, for each operation add a value to each the array element between two given indices, inclusive. Once all operations have been performed, return the maximum value in the array.
Example: n = 10, Queries = [[1,5,3],[4,8,7],[6,9,1]]
The following will be the resultant output after iterating through the array, Index 1-5 will have 3 added to it etc...:
[0,0,0, 0, 0,0,0,0,0, 0]
[3,3,3, 3, 3,0,0,0,0, 0]
[3,3,3,10,10,7,7,7,0, 0]
[3,3,3,10,10,8,8,8,1, 0]
Finally you output the max value in the final list:
[3,3,3,10,10,8,8,8,1, 0]
My current solution:
def Operations(size, Array):
ResultArray = [0]*size
Values = [[i.pop(2)] for i in Array]
for index, i in enumerate(Array):
#Current Values in = Sum between the current values in the Results Array AND the added operation of equal length
#Results Array
ResultArray[i[0]-1:i[1]] = list(map(sum, zip(ResultArray[i[0]-1:i[1]], Values[index]*len(ResultArray[i[0]-1:i[1]]))))
Result = max(ResultArray)
return Result
def main():
nm = input().split()
n = int(nm[0])
m = int(nm[1])
queries = []
for _ in range(m):
queries.append(list(map(int, input().rstrip().split())))
result = Operations(n, queries)
if __name__ == "__main__":
main()
Example input: The first line contains two space-separated integers n and m, the size of the array and the number of operations.
Each of the next m lines contains three space-separated integers a,b and k, the left index, right index and summand.
5 3
1 2 100
2 5 100
3 4 100
Compiler Error at Large Sizes:
Runtime Error
Currently this solution is working for smaller final lists of length 4000, however in order test cases where length = 10,000,000 it is failing. I do not know why this is the case and I cannot provide the example input since it is so massive. Is there anything clear as to why it would fail in larger cases?
I think the problem is that you make too many intermediary trow away list here:
ResultArray[i[0]-1:i[1]] = list(map(sum, zip(ResultArray[i[0]-1:i[1]], Values[index]*len(ResultArray[i[0]-1:i[1]]))))
this ResultArray[i[0]-1:i[1]] result in a list and you do it twice, and one is just to get the size, which is a complete waste of resources, then you make another list with Values[index]*len(...) and finally compile that into yet another list that will also be throw away once it is assigned into the original, so you make 4 throw away list, so for example lets said the the slice size is of 5.000.000, then you are making 4 of those or 20.000.000 extra space you are consuming, 15.000.000 of which you don't really need, and if your original list is of 10.000.000 elements, well just do the math...
You can get the same result for your list(map(...)) with list comprehension like
[v+Value[index][0] for v in ResultArray[i[0]-1:i[1]] ]
now we use two less lists, and we can reduce one list more by making it a generator expression, given that slice assignment does not need that you assign a list specifically, just something that is iterable
(v+Value[index][0] for v in ResultArray[i[0]-1:i[1]] )
I don't know if internally the slice assignment it make it a list first or not, but hopefully it doesn't, and with that we go back to just one extra list
here is an example
>>> a=[0]*10
>>> a
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
>>> a[1:5] = (3+v for v in a[1:5])
>>> a
[0, 3, 3, 3, 3, 0, 0, 0, 0, 0]
>>>
we can reduce it to zero extra list (assuming that internally it doesn't make one) by using itertools.islice
>>> import itertools
>>> a[3:7] = (1+v for v in itertools.islice(a,3,7))
>>> a
[0, 3, 3, 4, 4, 1, 1, 0, 0, 0]
>>>
I have 2 lists like the following:
a=[[1,0,1,0,1],[0,0,0,1,0],[1,1,0,0,0]]
b=[[1,0,0,0,1],[0,1,0,1,0],[1,1,0,1,0]]
I want to return true if all the sublists in b are present in a and vice versa.
That means a should be equal to b but indexes of the sublists can be different.
eg:
a=[[1,0,1,0,1],[0,0,0,1,0],[1,1,0,0,0]]
b=[[1,0,1,0,1],[1,1,0,0,0],[0,0,0,1,0]]
Above a and b are equal and comparison should return true. Also, the sublists will only contain a combination of 1s or 0s. How do I compare them?
I tried converting them to sets : set(a) but this is throwing an error.
Apart from that, when I tried the following code in a while loop, it gave an error
a=[[1,0,1,0,1],[0,0,0,1,0],[1,1,0,0,0]]
b=[[1,0,1,0,1],[1,1,0,0,0],[0,0,0,1,0]]
def sublists_equal(a, b):
return all(l for l in b if l in a)
print(sublists_equal(a, b))
The error was:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
I tried printing both the arrays to see what the problem was, they are printing like follows:
[[0 1 0 1 0]
[0 1 1 1 1]
[0 0 0 0 1]
[0 1 0 0 0]]
[array([0, 1, 0, 1, 0]), array([0, 0, 0, 0, 1]), array([0, 1, 1, 1, 1]), array([0, 1, 0, 0, 0])]
You could use the all() built-in function to check whether all sub-lists l of b can be found in a.
a=[[1,0,1,0,1],[0,0,0,1,0],[1,1,0,0,0]]
b=[[1,0,1,0,1],[1,1,0,0,0],[0,0,0,1,0]]
def sublists_equal(a, b):
return all(l for l in b if l in a)
print(sublists_equal(a, b))
Should you wanted to use sets, you would have to convert each sub-list to a tuple, which is a hashable type, and then compare their symmetric difference denoted by the ^ operator which returns the set of elements not found in both lists. If the symmetric difference is the empty set(), which is negated to True using the not operator, then the lists have equal sub-lists.
def sublist_equal2(a, b):
return not set([tuple(l) for l in a]) ^ set([tuple(l) for l in b])
print(sublist_equal2(a, b))
Output:
True
The easiest way is to sort the lists before comparing them:
def compare_lists(a, b):
return sorted(a) == sorted(b)
this handles cases where there are duplicate values.
If duplicates don't matter, and the sublists only contains 1 and 0, you could convert them to integers:
def sublists_to_integers(lst):
return [int(''.join(str(i) for i in item), 2) for item in lst]
def compare_lists(a, b):
return set(sublists_to_integers(a)) == set(sublists_to_integers(b))
which depending on your list size might be faster and/or use less memory.
...and compare it with another list to get the same item in the same index/position.
Eg.
a = [1, 2, 3, 4, 5]
b = [a, b, c, d, e]
I want the highest number in list a so:
5
And then, I compare it with list b to get the item, which is on the same position as the highest number in list a:
e
I apologize for the poorly worded question but this is the best I can explain it.
One-liner: b[a.index(max(a))]
However, this makes two pass through the list, i.e. first with max(a), and second with a.index.
The snippet below makes only one pass:
max_index, max_value = max(enumerate(a), key=lambda p: p[1])
print(b[max_index])
python has this great built in array function called index that will take care of what you need.
in your example: x = b[a.index(5)] which takes a and gets the index of 5 (which is 4) and then assigns the item in b at that index to the variable x so that you can do whatever evaluations you may need.
I know this is similar to Efficient way to compare elements in 2 lists, but I have an extension on the question basically.
Say I have two lists:
a = [1,2,4,1,0,3,2]
b = [0,1,2,3,4]
I want to find out the indices of a where the element is equal to each element of b.
For instance, I would want the sample output for b[1] to tell me that a = b[1] at [0,3].
A data frame output would be useful as well, something like:
b index_a
0 4
1 0
1 3
2 1
2 6
3 5
4 3
What I used before was:
b = pd.DataFrame(b)
a = pd.DataFrame(a)
pd.merge(b.reset_index(),a.reset_index(),
left_on=b.columns.tolist(),
right_on = a.columns.tolist(),
suffixes = ('_b','_a'))['index_b','index_a']]
However, I am unsure if this is necessary since these are for lists. ( I used this method previously when I was working with dataframes ).
I am doing this operation thousands of times with much larger lists so I am wondering if there is a more efficient method.
In addition, b is just list(range(X)) where in this case X = 5
If anyone has some input I'd greatly appreciate it!
Thanks
A very simple and efficient solution is to build a mapping from the values in the range 0..N-1 to indices of a. The mapping can be a simple list, so you end up with:
indices = [[] for _ in b]
for i, x in enumerate(a):
indices[x].append(i)
Example run:
>>> a = [1,2,4,1,0,3,2]
>>> b = [0,1,2,3,4]
>>> indices = [[] for _ in b]
>>> for i,x in enumerate(a):
... indices[x].append(i)
...
>>> indices[1]
[0, 3]
Note that b[i] == i so keeping the b list is pretty useless.
import collections
dd=collections.defaultdict(list)
for i,x in enumerate(a):
dd[x].append(i)
>>> sorted(dd.items())
[(0, [4]), (1, [0, 3]), (2, [1, 6]), (3, [5]), (4, [2])]
If b is sorted consecutive integers as you shown here, then bucket sort is most effective.
Otherwise, you may construct a hash table, with value b as the key, and construction a list of a's as values.
I'm not sure if this is efficient enough for your needs, but this would work:
from collections import defaultdict
indexes = defaultdict(set)
a = [1,2,4,1,0,3,2]
b = [0,1,2,3,4]
for i, x in enumerate(a):
indexes[x].add(i)
for x in b:
print b, indexes.get(x)
I need to take a list add 1 to the first number and then replace the remaining numbers with a 0. I have tried many different ways, but I either only replace the second item or my first item goes away or it doesn't simply work.
Here is what I have:
key2=[8,10,10,10]
key2[0]+=1
for item in key2[1:]:
item=0
key2.append(item)
This is giving me
[9, 10, 10, 10, 0, 0, 0]
but I need to get rid of all the 10s. How do I do a for loop to get this result [9,0,0,0]?
for index in range(1, len(key2)):
key2[index]=0
In this code we are replacing the item from second index to last index by 0.
one liner, using enumerate()
lst = [ele+1 if i == 0 else 0 for i, ele in enumerate(lst)]
>>> key2=[8,10,10,10]
>>> key2[0], key2[1:] = key2[0]+1, [ 0 for item in key2[1:]]
>>> key2
[9, 0, 0, 0]
You can use range() to iterate over the indices, till the length of the list, and replace each element by 0.
Code -
for i in range(1, len(key2)):
key2[i] = 0
Example/Demo -
>>> key2=[8,10,10,10]
>>>
>>> key2[0]+=1
>>> for i in range(1, len(key2)):
... key2[i] = 0
...
>>> key2
[9, 0, 0, 0]
All you are doing is pushing more zeroes to the end of the list, not overwriting the 10s you want to delete. Instead, try the following:
key2=[8,10,10,10]
key2[0]+=1
for num in range (1, len(key2)):
key2[num] = 0
>>> for num in range (1, len(key2)):
... key2[num] = 0
...
>>> key2
[9, 0, 0, 0]
>>>
I like functional programming:
key2 = [8, 10, 10, 10]
key2 = map(lambda (i, v): 0 if i > 0 else v+1, enumerate(key2))
>>> key2
[9, 0, 0, 0]
map runs through every element of a given list and applies a given function to the element. In my case its the lambda function.
I use enumerate to get the index of the item in the list with the item so I get both information in my lambda function.
Detailed explanation:
enumerate creates a generator, that for each item of the given list or iterable returns a tuple containing the index of the element in the first position and the element in the second. In the example, it would return:
[(0, 8), (1, 10), ...]
lambda defines an inline function. In our example, the function takes a tuple and unpacks its values into i and v. If i (the index of our element) is bigger than 0 return 0 if not, return v+1.
map is a function, that applies a given function (in our case the lambda function) to every element of a given list or iterable (in our case the result of the enumerate). map creates a new list with the returned elements of the function.
As enumerate and map are generators, we are good for memory. However, we basically create a duplicate of the list in memory. We free the memory after reassigning it. So if memory is an issue, don't do this. If not, functional programming is nice :)