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.
Related
I am trying to see if groups of three with consecutive elements have a zigzag pattern. Add to an empty list "1" for a zig, "1" for a zag, or "0" for neither. It seems to satisfy my first "if" condition and my "else" statement but never the middle. I've tried it as two if statement, one if and one elif, and nested. The answer should be [1,1,0] but I can only get [1,0] or no output and sometimes " index out of range".
input [1,2,1,3,4]
output [1,1,0]
def solution(numbers):
arr = []
for i in range(len(numbers)-2):
if numbers[i+1] > numbers[i] and numbers[i+2]:
arr.append(1)
if numbers[i+1] < numbers[i] and numbers[i+2]:
arr.append(1)
else:
arr.append(0)
return arr
You can use zip to combine elements 3 by 3 and compare each triplet to check if the middle element is either greater than both its neighbours or smaller than both of them:
numbers = [1,2,1,3,4]
result = [int((a-b)*(b-c)<0) for a,b,c in zip(numbers,numbers[1:],numbers[2:])]
print(result) # [1, 1, 0]
zip will combine items offset by 0, 1 and 2 yielding the following triplets:
numbers [1,2,1,3,4]
numbers[1:] [2,1,3,4]
numbers[2:] [1,3,4]
zip(): * * * <-- 3 triplets (extras are ignored)
a,b,c a-b b-c (a-b)*(b-c) int(...<0)
-------
(1,2,1) -1 1 -1 1
(2,1,3) 1 -2 -2 1
(1,3,4) -2 -1 2 0
Break the solution into two parts:
Build a list of the differences between consecutive numbers (the zigs and zags).
Return a list of the differences between consecutive zigs and zags (the zigzags).
You can use zip with slices to iterate over each pair of consecutive elements:
def zig_zags(numbers):
zigzags = [(a - b) // abs(a - b) for a, b in zip(numbers, numbers[1:])]
return [int(a and b and a != b) for a, b in zip(zigzags, zigzags[1:])]
print(zig_zags([1, 2, 1, 3, 4])) # [1, 1, 0]
To break this down a little bit more, let's use the REPL to look at how zip with the slice works:
>>> numbers = [1, 2, 1, 3, 4]
>>> numbers[1:]
[2, 1, 3, 4]
>>> [(a, b) for a, b in zip(numbers, numbers[1:])]
[(1, 2), (2, 1), (1, 3), (3, 4)]
The slice [1:] takes the list starting with the second element, and zip takes two lists (the original list and the sliced version that's offset by one) and yields one element from each at a time -- so all together, we're getting pairs of consecutive elements.
Now let's take that same expression but subtract a and b rather than turning them into tuples:
>>> [a - b for a, b in zip(numbers, numbers[1:])]
[-1, 1, -2, -1]
Negative numbers show where the original list was decreasing (zigging) and positive numbers show where it was increasing (zagging). (If it was neither zigging nor zagging there'd be a zero.) It'll be easier to compare the zigs and zags if we normalize them:
>>> [(a - b) // abs(a - b) for a, b in zip(numbers, numbers[1:])]
[-1, 1, -1, -1]
Now each "zig" is -1 and each "zag" is +1. So now let's see where the zigs follow the zags:
>>> zigzags = [(a - b) // abs(a - b) for a, b in zip(numbers, numbers[1:])]
>>> [(a, b) for a, b in zip(zigzags, zigzags[1:])]
[(-1, 1), (1, -1), (-1, -1)]
>>> [a != b for a, b in zip(zigzags, zigzags[1:])]
[True, True, False]
Same exact technique with zip and [1:] as before, but now we're looking at the zigs and zags that we computed in the first step. Because we normalized them, all we need to do is look at whether they're equal to each other.
We should also specifically exclude cases where there was no zig or zag, i.e. where a or b is zero. That just looks like:
>>> [a and b and a != b for a, b in zip(zigzags, zigzags[1:])]
[True, True, False]
Finally, since we wanted our output to be in terms of 1 and 0 instead of True and False, we need to convert that. Conveniently, when you convert True to an int it becomes 1 and False becomes 0, so we can just wrap the whole thing in int:
>>> [int(a and b and a != b) for a, b in zip(zigzags, zigzags[1:])]
[1, 1, 0]
Thanks everyone!
It was suggested I define my end range to avoid index out of range errors ( changed to len(numbers)-2) and that I change my formatting from "numbers[i+1] < numbers[i] and numbers[i+2]" to "numbers[i] > numbers[i+1] < numbers[i+2]". Also suggested I try the zip function which I will learn for next time.
You've got a sliding window here.
You're getting IndexError because your code has for i in range(len(numbers)), and then you ask for numbers[i+2]. To prevent this, reduce the range:
for i in range(len(numbers) - 2):
<do checks on numbers[i], numbers[i+1], numbers[i+2]>
But you may prefer to zip some slices together:
for a, b, c in zip(numbers, numbers[1:], numbers[2:]):
<do checks on a, b, c>
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 run python neural network prediction expecting one hot result and got back numbers as follow:
[[0.33058667182922363, 0.3436272442340851, 0.3257860243320465],
[0.32983461022377014, 0.3487854599952698, 0.4213798701763153],
[0.3311253488063812, 0.3473075330257416, 0.3215670585632324],
[0.38368630170822144, 0.35151687264442444, 0.3247968554496765],
[0.3332786560058594, 0.343686580657959, 0.32303473353385925]]
how can I convert the array into one hot result, i.e.
[[0,1,0],
[0,0,1],
[0,1,0],
[1,0,0]
[0,1,0]]
By one hot result I assume you want max value of each sub-list to be 1 and rest to be 0 (based on the pattern in current result). You may do it using list comprehension as:
>>> [[int(item == max(sublist)) else 0 for item in sublist] for sublist in my_list]
# ^ converts bool value returned by `==` into `int`. True -> 1, False -> 0
[[0, 1, 0], [0, 0, 1], [0, 1, 0], [1, 0, 0], [0, 1, 0]]
where my_list is your initial list.
But in the above approach, you will be calculating max() each time while iteration over sub-list. Better way will be to do it like:
def get_hot_value(my_list):
max_val = max(my_list)
return [int(item == max_val) for item in my_list]
hot_list = [get_hot_value(sublist) for sublist in my_list]
Edit: If you are supposed to have just one 1 in the list (in case of more than 1 element of maximum value), you may modify the get_hot_value function as:
def get_hot_value(my_list):
max_val, hot_list, is_max_found = max(my_list), [], False
for item in my_list:
if item == max_val and not is_max_found:
hot_list.append(1)
else:
hot_list.append(0)
is_max_found = True
return hot_list
The other solutions are good, and solve the problem. Alternatively, if you have numpy,
import numpy as np
n = [[0.33058667182922363, 0.3436272442340851, 0.3257860243320465],
[0.32983461022377014, 0.3487854599952698, 0.4213798701763153],
[0.3311253488063812, 0.3473075330257416, 0.3215670585632324],
[0.38368630170822144, 0.35151687264442444, 0.3247968554496765],
[0.3332786560058594, 0.343686580657959, 0.32303473353385925]]
max_indices = np.argmax(n,axis=1)
final_values = [n[i] for i in max_indices]
argmax is able to find the index of the maximum value in that row, then you just need to do one list comprehension over that. Should be pretty fast I guess?
I would suggest this:
n = [[0.33058667182922363, 0.3436272442340851, 0.3257860243320465],
[0.32983461022377014, 0.3487854599952698, 0.4213798701763153],
[0.3311253488063812, 0.3473075330257416, 0.3215670585632324],
[0.38368630170822144, 0.35151687264442444, 0.3247968554496765],
[0.3332786560058594, 0.343686580657959, 0.32303473353385925]]
hot_results = []
for row in n:
hot_index = row.index(max(row))
hot_result = [0] * len(row)
hot_result[hot_index] = 1
hot_results.append(hot_result)
print(hot_results)
With list a = [1, 2, 3, 5, 4] I wish to find the index of the nth largest value. function(a, 4) = 2 since 2 is the index of the 4th largest value. NOTE: Needs to function for lists containing 500 or more elements and works with looping.
You could index into the result of sorted(a) to find the n-th largest value:
>>> a = [1, 2, 3, 5, 4]
>>> n = 4
>>> x = sorted(a)[-n]
>>> x
2
Then use a.index() to find the element's index in the original list (assuming the elements are unique):
>>> a.index(x) + 1 # use 1-based indexing
2
P.S. If n is small, you could also use heapq.nlargest() to get the n-th largest element:
>>> import heapq
>>> heapq.nlargest(n, a)[-1]
2
If not using index and max (easiest way) i would just:
def funcion (a):
highest_value = [0, position]
for x in range(len(a),0,-1):
value = a.pop()
if value > highest_value[0]:
highest_value[0] = value
highest_value[1] = len(a)-x
return highest_value
This way, you would get the highest value and save it index at the same time, so it should be quite efficient. Using pop is much faster than looking from 0 to end, because access is backward.
I think you're using 1 based indexing. Assumes values are unique.
a.index(sorted(a)[4-1])+1
will give you 5.
I have an ascending list of integers e that starts from 0 and I would like to have a binary list b whose i-th element is 1 if and only if i belongs to e.
For example, if e=[0,1,3,6], then this binary list should be [1,1,0,1,0,0,1],
where the first 1 is because 0 is in e, the second 1 is because 1 is in e, the
third 0 is because 2 is not in e, and so on.
You can find my code for that below.
My question is: is there something built-in in python for that? If not, is my
approach the most efficient?
def list2bin(e):
b=[1]
j=1
for i in range(1, e[-1]+1):
if i==e[j]:
b.append(1)
j+=1
else:
b.append(0)
return(b)
This can be done with a list comprehension, and in case e is huge then better convert it to a set first:
>>> e = [0, 1, 3, 6]
>>> [int(i in e) for i in xrange(0, e[-1]+1)]
[1, 1, 0, 1, 0, 0, 1]
The in operator returns True/False if an item is found in the list, you can convert that bool to an integer using int. Note that for lists the in is O(N) operation, so if e is large then converting it to a set will provide you much more efficiency.
I don't think there are a built-in way to do that. But you can use List Comprehensions:
a = [ 1 if i in e else 0 for i in range(1, e[-1]+1) ]
Get fun.