Function is kicking out variable with 3, separate lists - python

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))

Related

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]

add value to each element of a multidimensional array

I want to know how I can add a value to each element of a NXN multidimensional array. I tried [x+1 for x in multiArray], but this one yields only for a 1D array.
Maybe something like this:
multiArray = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
addingArray=[]
for i in range(3):
for j in range(3):
addingArray.append(multiArray[j]+1) #(adding 1 to each element here)
But this seems to be wrong?
You're getting 1D array as result because you have addingArray as a simple list. So, you iterate over all the elements in your multiArray and add 1 to it and you're appending the result to a list.
For efficiency reasons, it is advisable to use NumPy for arrays. Then, you can simply use broadcasting to add value to each element of the array. Below is an illustration:
# input array
In [180]: multiArray = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# add 1 to each value of the array
In [181]: multiArray + 1
Out[181]:
array([[ 2, 3, 4],
[ 5, 6, 7],
[ 8, 9, 10]])
If you indeed want a plain python list as the result for some reasons, you can simply cast it to one:
In [182]: (multiArray + 1).tolist()
Out[182]: [[2, 3, 4], [5, 6, 7], [8, 9, 10]]
Indice-iteration
You need to have a inner list to get the inner results, and access the good value with multiArray[i][j], also don't use constant 3 take the habit to use object length
addingArray=[]
for i in range(len(multiArray)):
innerArray = []
for j in range(len(multiArray[i])):
innerArray.append(multiArray[i][j]+1)
addingArray.append(innerArray)
print(addingArray) # [[2, 3, 4], [5, 6, 7], [8, 9, 10]]
Value iteration
You can also iterate over the arra directly to simplify and don't both with indices
addingArray=[]
for inner in multiArray:
innerArray = []
for value in inner:
innerArray.append(value+1)
addingArray.append(innerArray)
List comprehension
And shorten it with list comprehension syntax
multiArray = [[v+1 for v in inner] for inner in multiArray]
print(multiArray) # [[2, 3, 4], [5, 6, 7], [8, 9, 10]]

How to split a numpy array based on a tuple content? [duplicate]

This question already has an answer here:
Create index list for np.split from the list that already has number for each section
(1 answer)
Closed 3 years ago.
Let's say I've got an array [0, 1, 2, 3, 4, 5, 6, 7] and a tuple: (3, 3, 2).
I'm looking for a way to split my array to 3 array based on my tuple data:
[0, 1, 2]
[3, 4, 5]
[6, 7]
I can write a simple code like this to get what I want, however I'm looking for a correct and pythonic way to do this:
I used lists for simplicity.
a = [0, 1, 2, 3, 4, 5, 6, 7]
b = (3, 3, 2)
pointer = 0
for i in b:
lst = []
for j in range(i):
lst.append(a[pointer])
pointer += 1
print(lst)
Or this one:
a = [0, 1, 2, 3, 4, 5, 6, 7]
b = (3, 3, 2)
pointer = 0
for i in b:
lst = a[pointer:pointer+i]
pointer += i
print(lst)
Results:
[0, 1, 2]
[3, 4, 5]
[6, 7]
you can use the split method of numpy
import numpy as np
a = [0, 1, 2, 3, 4, 5, 6, 7]
b = (3, 3, 2)
c = np.split(a, np.cumsum(b)[:-1])
for r in c:
print(r)
np.split(a, b) splits a by the indices in b along a given axis(0 by default).
If you don't want to modify your input list, you can use an iterator and the itertools module.
>>> from itertools import islice
>>> a = [0, 1, 2, 3, 4, 5, 6, 7]
>>> b = (3, 3, 2)
>>> i = iter(a)
>>> [list(islice(i, x)) for x in b]
[[0, 1, 2], [3, 4, 5], [6, 7]]
In the first step you create an iterator, which starts at the first element of a. Then you iterate in a list comprehension over your numbers in b and in each step you pull accordingly many elements from the iterator and store them in your result list.
One simpler way is this:
a = [0, 1, 2, 3, 4, 5, 6, 7]
b = (3, 3, 2)
for ind in b:
print(a[:ind])
a = a[ind:]
It loops through slice sizes in b while shortening the original array every time. You can easily append the resulting slices as sublists if you need them for something else. It's almost like one of your solutions except it doesn't use any extra variables and iterates directly through elements of b.
Also, I wouldn't call variables a and b - surely not in this case where variables have clear meanings that you can express through their names. More meaningful names lessen bugs number and make code more clear, becomes a real difference with larger/more complex code. I'd call a at least in_list and b slices, but with more context this could be better.
The most "concise" syntax would be :
ex_array = [0, 1, 2, 3, 4, 5, 6, 7]
extuple = (3, 3, 2)
result = [ex_array[sum(extuple[:iii]):sum(extuple[:iii])+extuple[iii]] for iii in range(len(extuple))]
result would be a list of the expected sub-lists
Re-using the pairwise function from Compare two adjacent elements in same list, you could also:
from itertools import accumulate
from more_itertools import pairwise
a = [0, 1, 2, 3, 4, 5, 6, 7]
b = (3, 3, 2)
[a[slice(*s)] for s in pairwise(accumulate((0,)+b))]
That begin said, the np.split answer is probably faster (and easier to read).

Python right to left diagonal list

I would like a list to be stored into another list from right to left diagonally without importing anything if possible
eg. list =
[[1, 4, 6]
[6, 3, 7]
[2, 7, 9]]
say I'd like to store [6, 3, 2] into another list, how would i go about doing it? I have tried many ways for hours and still cant find a solution
With a list comprehension:
l =[[1, 4, 6],
[6, 3, 7],
[2, 7, 9]]
diagonal = [row[-i] for i, row in enumerate(l, start=1)]
print(diagonal)
Output
[6, 3, 2]
The following snipped
l =[[1, 4, 6],
[6, 3, 7],
[2, 7, 9]]
d = len(l)
a = []
for i in range(0,d):
a.append(l[i][d-1-i])
print(a)
results in the output you expected:
[6, 3, 2]
You can use a list comprehension and use list indexing twice to select your row and column:
L = [[1, 4, 6],
[6, 3, 7],
[2, 7, 9]]
n = len(L)
res = [L[i][n-i-1] for i in range(n)]
# [6, 3, 2]
An alternative formulation is to use enumerate as per #OlivierMelançon's solution.
If you can use a 3rd party library, you can use NumPy to extract the diagonal of a flipped array:
import numpy as np
arr = np.array(L)
res = np.diag(np.fliplr(arr))
# array([6, 3, 2])
When you want to create a list out from another list, list comprehension is a very good way to go.
a = yourlist
print([a[i][(i+1)*-1] for i in range(len(a))])
This list comprehension loops through the lists taking the the furthes back integer and the second furthes back and so on.
Using numpy and rotate (90)
import numpy as np
list = [[1, 4, 6],[6, 3, 7],[2, 7, 9]]
np.diag(np.rot90(array))
Output :
array([6, 3, 2])
or without using numpy:
list = [[1, 4, 6],[6, 3, 7],[2, 7, 9]]
res=[]
i=-1
for elm in list :
res.append(elm[i])
i-=1
print res
#[6, 3, 2]

Random sample from list of lists

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]

Categories

Resources