Related
My very first post and question here...
So, let list_a be the list of lists:
list_a = [[2,7,8], [3,4,2], [5,10], [4], [2,3,5]...]
Let list_b be another list of integers: list_b = [5,7]
I need to exclude all lists in list_a, whose items include at least one item from list_b. The result from example above schould look like list_c = [[3,4,2], [4]...]
If list_b was not a list but a single number b, then one could define list_c in one line as:
list_c = [x for x in list_a if not b in x]
I am wondering, if it is possible to write an elegant one-liner also for the list list_b with several values in it. Of course, I can just loop through all list_b's values, but may be there exists a faster option?
Let's first consider the task of checking an individual element of list_a - such as [2,7,8] - because no matter what, we're conceptually doing to need a way to do that, and then we're going to apply that to the list with a list comprehension. I'll use a as the name for such a list, and b for an element of list_b.
The straightforward way to write this is using the any builtin, which works elegantly in combination with generator expressions: any(b in a for b in list_b).
The logic is simple: we create a generator expression (like a lazily-evaluated list comprehension) to represent the result of the b in a check applied to each b in list_b. We create those by replacing the [] with (); but due to a special syntax rule we may drop these when using it as the sole argument to a function. Then any does exactly what it sounds like: it checks (with early bail-out) whether any of the elements in the iterable (which includes generator expressions) is truthy.
However, we can likely do better by taking advantage of set intersection. The key insight is that the test we are trying to do is symmetric; considering the test between a and list_b (and coming up with another name for elements of a), we could equally have written any(x in list_b for x in a), except that it's harder to understand that.
Now, it doesn't help to make a set from a, because we have to iterate over a anyway in order to do that. (The generator expression does that implicitly; in used for list membership requires iteration.) However, if we make a set from list_b, then we can do that once, ahead of time, and just have any(x in set_b for x in a).
But that, in turn, is a) as described above, hard to understand; and b) overlooking the built-in machinery of sets. The operator & normally used for set intersection requires a set on both sides, but the named method .intersection does not. Thus, set_b.intersection(a) does the trick.
Putting it all together, we get:
set_b = set(list_b)
list_c = [a for a in list_a if not set_b.intersection(a)]
You can write the logic all sublists in A where none of the elements of B are in the sublist with a list comprehension like:
A = [[2,7,8], [3,4,2], [5,10], [4], [2,3,5]]
B = [5,7]
[l for l in A if not any(n in l for n in B)]
# [[3, 4, 2], [4]]
The condition any(n in l for n in B) will be true if any element, n, of B is in the sublist, l, from A. Using not we can take the opposite of that.
Mark's answer is good but hard to read.
FYI, you can also leverage sets:
>>> set_b = set(list_b)
>>> [l for l in list_a if not set_b.intersection(l)]
[[3, 4, 2], [4]]
I'm doing my programming coursework, and I've come across an issue
gamecentre1 = [winnerscore, winner]
organise = []
organise.extend([gamecentre1])
from operator import attrgetter, itemgetter
sorted(organise, key= itemgetter(0))
print(organise)
f = open("gameresults.txt","w")
f.write("Here are the winners of the games: \n")
f.write(str(organise))
f.write("\n")
f.close()
I'm trying to add two variables to a list, and add that list to another list. Then, I want to organise that larger list based off of the integer variable of the sublist (the integer is the winnerscore). But, the problem is that I haven't been able to organise them properly, and I worry that since I have to append the same list with the same variables to the larger list without overwriting the existing list in it, the larger list will just have the same values over and over again.
This is because I want to store the variables every time the program runs, without getting rid of the values of the variable from the previous game.
How do I do this?
I'm trying to add two variables to a list, and add that list to another list. Then, I want to organise that larger list based off of the integer variable of the sublist
It sounds like what you want is a nested list - a big list of small lists, such that each small list is independent of the others. The key problem in your code right now that's blocking you from accomplishing this is extend() - this is essentially list concatenation, which isn't what you want. For example,
x = [1, 2]
x.extend([3, 4]) # x == [1, 2, 3, 4]
Instead, try using append(), which adds its argument as the next value in the list. For example:
x = []
x.append([3, 4]) # [[3, 4]]
x.append([1, 2]) # [[3, 4], [1, 2]]
Now in the above example, we have a list x that's two elements long, and each of those elements is itself a list of two elements. Now we can plug that into sort:
y = sorted(x, key=lambda i: i[0])
print(y)
# [[1, 2], [3, 4]]
(the lambda i: i[0] is really just a more elegant way of what you're doing with itemgettr(0) - it's a lambda, a small inline function, that takes one argument i and returns the 0th element of i. In this case, the i that gets passed in is one of the smaller lists).
Now you have a sorted list of smaller lists, and you can do whatever you need with them.
I have two flat lists where one of them contains duplicate values.
For example,
array1 = [1,4,4,7,10,10,10,15,16,17,18,20]
array2 = [4,6,7,8,9,10]
I need to find values in array1 that are also in array2, KEEPING THE DUPLICATES in array1.
Desired outcome will be
result = [4,4,7,10,10,10]
I want to avoid loops as actual arrays will contain over millions of values.
I have tried various set and intersect combinations, but just couldn't keep the duplicates..
What do you mean you don't want to use loops? You're going to have to iterate over it one way or another. Just take in each item individually and check if it's in array2 as you go:
items = set(array2)
found = [i for i in array1 if i in items]
Furthermore, depending on how you are going to use the result, consider having a generator:
found = (i for i in array1 if i in array2)
so that you won't have to have the whole thing in memory all at once.
There following will do it:
array1 = [1,4,4,7,10,10,10,15,16,17,18,20]
array2 = [4,6,7,8,9,10]
set2 = set(array2)
print [el for el in array1 if el in set2]
It keeps the order and repetitions of elements in array1.
It turns array2 into a set for faster lookups. Note that this is only beneficial if array2 is sufficiently large; if array2 is small, it may be more performant to keep it as a list.
Following on from #Alex's answer, if you also want to extract the indices for each token, then here's how:
found = [[index,i] for index,i in enumerate(array1) if i in array2]
I have a following problem while trying to do some nodal analysis:
For example:
my_list=[[1,2,3,1],[2,3,1,2],[3,2,1,3]]
I want to write a function that treats the element_list inside my_list in a following way:
-The number of occurrence of certain element inside the list of my_list is not important and, as long as the unique elements inside the list are same, they are identical.
Find the identical loop based on the above premises and only keep the
first one and ignore other identical lists of my_list while preserving
the order.
Thus, in above example the function should return just the first list which is [1,2,3,1] because all the lists inside my_list are equal based on above premises.
I wrote a function in python to do this but I think it can be shortened and I am not sure if this is an efficient way to do it. Here is my code:
def _remove_duplicate_loops(duplicate_loop):
loops=[]
for i in range(len(duplicate_loop)):
unique_el_list=[]
for j in range(len(duplicate_loop[i])):
if (duplicate_loop[i][j] not in unique_el_list):
unique_el_list.append(duplicate_loop[i][j])
loops.append(unique_el_list[:])
loops_set=[set(x) for x in loops]
unique_loop_dict={}
for k in range(len(loops_set)):
if (loops_set[k] not in list(unique_loop_dict.values())):
unique_loop_dict[k]=loops_set[k]
unique_loop_pos=list(unique_loop_dict.keys())
unique_loops=[]
for l in range(len(unique_loop_pos)):
unique_loops.append(duplicate_loop[l])
return unique_loops
from collections import OrderedDict
my_list = [[1, 2, 3, 1], [2, 3, 1, 2], [3, 2, 1, 3]]
seen_combos = OrderedDict()
for sublist in my_list:
unique_elements = frozenset(sublist)
if unique_elements not in seen_combos:
seen_combos[unique_elements] = sublist
my_list = seen_combos.values()
you could do it in a fairly straightforward way using dictionaries. but you'll need to use frozenset instead of set, as sets are mutable and therefore not hashable.
def _remove_duplicate_lists(duplicate_loop):
dupdict = OrderedDict((frozenset(x), x) for x in reversed(duplicate_loop))
return reversed(dupdict.values())
should do it. Note the double reversed() because normally the last item is the one that is preserved, where you want the first, and the double reverses accomplish that.
edit: correction, yes, per Steven's answer, it must be an OrderedDict(), or the values returned will not be correct. His version might be slightly faster too..
edit again: You need an ordered dict if the order of the lists is important. Say your list is
[[1,2,3,4], [4,3,2,1], [5,6,7,8]]
The ordered dict version will ALWAYS return
[[1,2,3,4], [5,6,7,8]]
However, the regular dict version may return the above, or may return
[[5,6,7,8], [1,2,3,4]]
If you don't care, a non-ordered dict version may be faster/use less memory.
I am trying to create a 2d matrix so that each cell contains a list of strings.
Matrix dimensions are known before the creation and I need to have access to any element from the beginning (not populating a matrix dynamically). I think some kind of pre-allocation of space is needed.
For example, I would like to have a 2X2 matrix:
[['A','B'] ['C'];
['d'] ['e','f','f']]
with support of traditional matrix access operations, like
(Matrix[2][2]).extend('d')
or
tmp = Matrix[2][2]
tmp.extend('d')
Matrix[2][2] = tmp
to manipulate with cells content.
How to accomplish it in python?
Just as you wrote it:
>>> matrix = [["str1", "str2"], ["str3"], ["str4", "str5"]]
>>> matrix
[['str1', 'str2'], ['str3'], ['str4', 'str5']]
>>> matrix[0][1]
'str2'
>>> matrix[0][1] += "someText"
>>> matrix
[['str1', 'str2someText'], ['str3'], ['str4', 'str5']]
>>> matrix[0].extend(["str6"])
>>> matrix[0]
['str1', 'str2someText', 'str6']
Just think about 2D matrix as list of the lists. Other operations also work fine, for example,
>>> matrix[0].append('value')
>>> matrix[0]
[0, 0, 0, 0, 0, 'value']
>>> matrix[0].pop()
'value'
>>>
You can either do it with the basic:
matrix = [
[["s1","s2"], ["s3"]],
[["s4"], ["s5"]]
]
or you can do it very genericially
from collections import defaultdict
m = defaultdict(lambda : defaultdict(list))
m[0][0].append('s1')
In the defaultdict case you have a arbitrary matrix that you can use, any size and all the elements are arrays, to be manipulated accordingly.
First of all, what you describe is actually a 3 dimensional matrix since each 'cell' also has a dimension whose kth element of the jth column of the ith row could be accessed via matrix[i][j][k].
Regardless, if you'd like to preallocate a 2X2 matrix with every cell initialized to an empty list, this function will do it for you:
def alloc_matrix2d(W, H):
""" Pre-allocate a 2D matrix of empty lists. """
return [ [ [] for i in range(W) ] for j in range(H) ]
However you might think it's not working because I noticed that you said that you would like to have a 2X2 matrix like this:
[
[
['A','B'], ['C']
],
[
['d'], ['e','f','f']
]
]
and be able to use "traditional matrix access operations" to do this to it:
(Matrix[2][2]).extend('d')
Problem is that won't work even for the matrix shown and still wouldn't for one preallocated to 2X2 since both the row and column dimensions are out of range in either case. In Python all sequences are indexed from zero, so valid indices for a matrix with two rows of two elements each are [0][0], [0][1], [1][0], and [1][1] (ignoring possible negative indices which have a special meaning in Python). So using Matrix[2][2] is an attempt to access the third column of the third row of the matrix which don't exist and wouldn't even in a preallocated one with dimensions of 2X2.
Everything would be fine if you changed that statement to something like this using one of the valid pairs of index values (and with unnecessary parentheses removed):
Matrix[1][1].extend('d')
since it would not raise an IndexError and instead would result in the 2X2 matrix becoming:
[
[
['A', 'B'], ['C']
],
[
['d'], ['e', 'f', 'f', 'd']
]
]
Bonus Utility
You didn't ask for one, but here's a handy function I wrote to help printing out arbitrarily sized 2D matrices of any type (represented as nested lists):
def repr_matrix2d(name, matrix):
lines = ['{} = ['.format(name)]
rows = []
for row in range(len(matrix)):
itemreprs = [repr(matrix[row][col]) for col in range(len(matrix[row]))]
rows.append('\n [\n {}\n ]'.format(', '.join(itemreprs)))
lines.append('{}\n]'.format(','.join(rows)))
return ''.join(lines)
Hope this helps.
One option is to write your own class, where you overload the [] operator. Take a look for that in here: http://www.penzilla.net/tutorials/python/classes/ .
Acessing a 2d elment in 1d is y * rowSize + x. Extending the elements by writing an append function, which would use append rowSize times.
If you want to create a 2d matrix and you need to preallocate than, you could do the following:
x,y = 3,3
A = [ [None]*x for i in range(y) ]
You can replace None with the value you want. And you can use .extend to add additional values.
Here's some minimal example that extends 2d list of lists:
my_list = [ [ [1] for x in range(4) ] for j in range(2) ]
print('initial list is ', my_list)
my_list[0][1].append(9)
print('list after extension is ', my_list)
and the results are
initial list is [[[1], [1], [1], [1]], [[1], [1], [1], [1]]]
list after extension is [[[1], [1, 9], [1], [1]], [[1], [1], [1], [1]]]
Hey guys not sure if this is helpful or not but this is how I generated a 2d list with python3.4 hope this is helpful
list=[]
list1=[]
list2=[]
list3=[]
answer1='yes'
answer2='yes'
answer3='yes'
while answer1=='yes':
item1=input("Please input a list element for your first list:")
answer1=input("Do you want to continue:")
list1.append(item1)
while answer2=='yes':
item2=input("Please input a list element for your second list:")
answer2=input("Do you want to continue:")
list2.append(item2)
while answer3=='yes':
item3=input("Please input a list element for your third list:")
answer3=input("Do you want to continue:")
list3.append(item3)
list.append(list1)
list.append(list2)
list.append(list3)
print(list)