Random sample from list of lists - python

In python, I have a list of lists, x, like so: [[1, 2, 3],[4, 5, 6], [7, 8, 9]]
I have another list, y, like so [1, 2, 3, 4, 5, 6, 7, 8, 9]
I need to get 2 random items from y that are not together in a list in x, so I can switch them around in x, with the goal being something like [[1, 2, 9], [4, 5, 6], [7, 8, 3]]. My current method is as follows:
done = False
while not done:
switchers = random.sample(y, 2)
if indexInCourse(x, switchers[0]) != indexInCourse(course, switchers[1]):
done = True
indexInCourse is a function that returns which list an item is in in a list of lists, so for (x, 1) it will return 0. The goal is for switchers to be 2 different numbers that are in different lists in the whole, so like [1, 9] or [4, 7]. My current method works, but is very slow for the large amount of lists I have going through it. Does anyone know of a more pythonic way to do this?

Why not randomly pick two distinct lists from x first and then swap a random choice of two elements between them?
lists = random.sample(x, 2)
# now we swap two random elements between lists[0], lists[1]

Related

Split a list into multiple ones

I am trying to split a list into multiple ones. The original list lst should be split on every element that is present in a second list, split_on.
Example:
lst = [1, 2, 3, 4, 5, 6, 7, 8]
split_on = [3, 4, 7]
should yield:
[[1,2,3],[3,4],[4,5,6,7],[7,8]]
Note that both lst and split_on do not contain duplicate elements and that any item of split_on is also an item of lst. Finally, the order of the elements of split_on can be random.
How about the following:
a = [1,2,3,4,5,6,7,8]
b = [4,3,7]
res = [[]]
for i in a:
res[-1].append(i)
if i in b:
res.append([i])
print(res) # [[1, 2, 3], [3, 4], [4, 5, 6, 7], [7, 8]]
Note that since b is only used for membership tests and the order does not matter, you could consider converting it to a set so that the approach scales better.

Transpose an already flattened square matrix

Given a square matrix represented as a list of lists, you can transpose it:
>>> l = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> l_T = list(map(list, zip(*l)))
>>> l_T
[[1, 4, 7], [2, 5, 8], [3, 6, 9]]
You can then flatten a list of lists using a list comprehension:
>>> v = [i for j in l for i in j]
>>> v_T = [i for j in l_T for i in j]
>>> v
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> v_T
[1, 4, 7, 2, 5, 8, 3, 6, 9]
My question is, is there a way to take the flattened list version of a square matrix, and rearrange it so it becomes the transposed version? Here, that would be to get from v to v_T without going back through a list of lists. I have tried to map out the relationship between the matrix position and the list indices, but I am not seeing the pattern, let alone one that would generalize to lists of any (square) length.
In order to try to avoid any XY problems: my original goal was to be able to take some simple list of list matrices and iterate over them in different ways (i.e. left>right then top>bottom versus top>bottom then left>right). And if your starting point is l, then it is easy to just create the transpose and unpack. But I am imagining you have the flattened matrix (v) as a starting point, and you want to compute v_T directly. So I am really more curious about that algorithm now, and how to do so in Python.
Start by finding the square root of the lists' length, and take slices of the list iteratively, starting on different lags until you've sliced all columns (or what would be the columns in a transposed 2D array):
def transpose_flat_list(l):
n = int(len(l)**.5)
return [v for i in range(n) for v in l[i::n]]
For the shared example:
l = [1, 2, 3, 4, 5, 6, 7, 8, 9]
transpose_flat_list(l)
# [1, 4, 7, 2, 5, 8, 3, 6, 9]
This could easily be done in NumPy too by reshaping and raveling in fortran order as:
def transpose_flat_list_numpy(l):
n = int(len(l)**.5)
return np.array(l).reshape(n,n).ravel('F').tolist()
transpose_flat_list_numpy(l)
# [1, 4, 7, 2, 5, 8, 3, 6, 9]

Function is kicking out variable with 3, separate lists

For the program I am writing my goal is to call a function, give it 2 values and then have it spit back lists based on those 2 numbers. Here's what I have so far,
import numpy as np
def list_maker (n, m):
for n in range(n):
l = list(np.random.randint(1,9, m))
print(l)
My goal is to type "list_maker(3,5)" and have it output 3 lists, each with 5 elements. I want to keep using numpy so I can learn more about it rather than another type of operation. Whenever I call the function my out it,
list_maker(3,5)
[2, 7, 1, 5, 6]
[8, 5, 1, 3, 5]
[8, 2, 6, 3, 7]
However, I can not specifically change one element in one list, if I do l[0] = "Blank", all the elements at 0 position turn to blank and I can't do [0],[1]....
Any idea how to get an output like,
list_maker(3,5)
[[2, 7, 1, 5, 6],
[8, 5, 1, 3, 5],
[8, 2, 6, 3, 7]]
Where I can then specifically edit one element in one of the lists done by numpy?
Thank you for all the replies!
you want to return a list of lists. A simple list comprehension would work:
import numpy as np
def list_maker (n, m):
return [list(np.random.randint(1,9, m)) for _ in range(n)]
then:
>>> list_maker(3,5)
[[1, 7, 2, 5, 7], [3, 5, 5, 7, 7], [8, 5, 1, 1, 1]]
At the moment your function is just printing the lists and not returning them.
And I'm not entirely sure of your intent; at the moment you're not creating a numpy array, but a list. More specifically, you're creating a list of 3 lists, not 3 separate lists.
You could create a numpy array by passing the n, m values directly to numpy's randint:
np.random.randint(1,9, size=(n, m))

How can I insert each object from one ordered list into into another nested list?

Using Python 3.7, I have two lists, one nested and one that is not, and I would like to extract the strings that are ordered in one list, and place each into a corresponding ordered nested list. Once the nested lists have been merged, I plan to unpack them into a table.
I have tried to perform a nested for-loop where I iterate through the nested loop to isolate the nested lists, and then a second for loop to extract each string object from its regular (unnested) list. My attempts to insert the string into the nested list end up either iterating through each character in the string, or it adds the entire list of strings into the nested lists. I've tried some different list comprehension attempts with zip, but being new at Python I've not yet mastered the syntax to traverse the lists.
A very simple attempt that hopefully explains what I am trying to accomplish.
a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
b = ['1-10', '10-20', '20-30']
for i in a:
for j in b:
i.insert(0, j)
print(a)
>>> [['1-10', 1, 2, 3], ['10-20', 4, 5, 6], ['20-30', 7, 8, 9]]
Use zip in a list-comprehension:
[[y] + x for x, y in zip(a, b)]
Example:
a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
b = ['1-10', '10-20', '20-30']
print([[y] + x for x, y in zip(a, b)])
# [['1-10', 1, 2, 3], ['10-20', 4, 5, 6], ['20-30', 7, 8, 9]]
Or use unpacking:
print([[y, *x] for x, y in zip(a, b)])
Output:
[['1-10', 1, 2, 3], ['10-20', 4, 5, 6], ['20-30', 7, 8, 9]]

Why the results are different from using merge(lista+listb) [duplicate]

This question already has answers here:
(Python) adding a list to another without the brackets
(3 answers)
Closed 7 years ago.
Here I'm trying to merge this two lists, making one whit all items.
n = [[1, 2, 3], [4, 5, 6, 7, 8, 9]]
def flatten(n):
s=[]
for x in n:
s.append(x)
return s
print flatten(n)
I'm trying to have as a result
[1,2,3,4,5,6,7,8,9]
but I'm getting
[[1, 2, 3], [4, 5, 6, 7, 8, 9]]
I dont understand why, I think I'm clearly assigning each value to the list 's' in the for loop.
You're appending to the list. Each sublist is appended to the new list as its own item, exactly the way it was originally. You want to extend the list instead:
s.extend(x)
Use extend, instead of append
n = [[1, 2, 3], [4, 5, 6, 7, 8, 9]]
def flatten(n):
s=[]
for x in n:
s.extend(x)
return s
print flatten(n)
Best of luck.
You should be using list.extend, append is appending each sublist not adding just the contents. x is each sublist so just appending the sublist is obviously going to give you a list of lists again.
You can also use itertools.chain to flatten the list:
n = [[1, 2, 3], [4, 5, 6, 7, 8, 9]]
print(list(chain.from_iterable(n)))
Or use a list comp:
n = [[1, 2, 3], [4, 5, 6, 7, 8, 9]]
print([ele for sub in n for ele in sub])

Categories

Resources