Change randomly half of the values of list - python

I'm working on 2D list on python and try to hide some values from the grid:
Imagine this is the grid:
[[0, 0, 1, 1],
[0, 1, 0, 1],
[1, 0, 1, 0],
[1, 1, 0, 0]]
the result I'm getting with this code:
def startingArray(self,grid_copy):
for i in range (len(grid_copy)):
n= self.CELL
if n>len(grid_copy):
grid_copy[i]=[2 for i in grid_copy]
else:
for i in range(n):
position=random.randrange(0,len(grid_copy[i]))
grid_copy[i][position]= 2
[[2, 0, 1, 2],
[2, 2, 2, 1],
[2, 0, 2, 2],
[2, 1, 2, 2]]
it's fine but, I want something where can hide exactly the half of the values randomly?
Any ideas?

Try this
def startingArray(self,grid_copy):
for row in grid_copy:
prevItems = []
for i in range(len(row)/2+1):
if (i not in prevItems):
row[random.randint(0, len(row) - 1)] = 2
prevItems.append(i)
I didn't try this. But I think this will do what you expect.

Related

Compute distances between all points in array efficiently using Python

I have a list of N=3 points like this as input:
points = [[1, 1], [2, 2], [4, 4]]
I wrote this code to compute all possible distances between all elements of my list points, as dist = min(∣x1−x2∣,∣y1−y2∣):
distances = []
for i in range(N-1):
for j in range(i+1,N):
dist = min((abs(points[i][0]-points[j][0]), abs(points[i][1]-points[j][1])))
distances.append(dist)
print(distances)
My output will be the array distances with all the distances saved in it: [1, 3, 2]
It works fine with N=3, but I would like to compute it in a more efficiently way and be free to set N=10^5.
I am trying to use also numpy and scipy, but I am having a little trouble with replacing the loops and use the correct method.
Can anybody help me please? Thanks in advance
The numpythonic solution
To compute your distances using the full power of Numpy, and do it
substantially faster:
Convert your points to a Numpy array:
pts = np.array(points)
Then run:
dist = np.abs(pts[np.newaxis, :, :] - pts[:, np.newaxis, :]).min(axis=2)
Here the result is a square array.
But if you want to get a list of elements above the diagonal,
just like your code generates, you can run:
dist2 = dist[np.triu_indices(pts.shape[0], 1)].tolist()
I ran this code for the following 9 points:
points = [[1, 1], [2, 2], [4, 4], [3, 5], [2, 8], [4, 10], [3, 7], [2, 9], [4, 7]]
For the above data, the result saved in dist (a full array) is:
array([[0, 1, 3, 2, 1, 3, 2, 1, 3],
[1, 0, 2, 1, 0, 2, 1, 0, 2],
[3, 2, 0, 1, 2, 0, 1, 2, 0],
[2, 1, 1, 0, 1, 1, 0, 1, 1],
[1, 0, 2, 1, 0, 2, 1, 0, 1],
[3, 2, 0, 1, 2, 0, 1, 1, 0],
[2, 1, 1, 0, 1, 1, 0, 1, 0],
[1, 0, 2, 1, 0, 1, 1, 0, 2],
[3, 2, 0, 1, 1, 0, 0, 2, 0]])
and the list of elements from upper diagonal part is:
[1, 3, 2, 1, 3, 2, 1, 3, 2, 1, 0, 2, 1, 0, 2, 1, 2, 0, 1, 2, 0, 1, 1, 0, 1, 1,
2, 1, 0, 1, 1, 1, 0, 1, 0, 2]
How faster is my code
It turns out that even for such small sample like I used (9
points), my code works 2 times faster. For a sample of 18 points
(not presented here) - 6 times faster.
This difference in speed has been gained even though my function
computes "2 times more than needed" i.e. it generates a full
array, whereas the lower diagonal part of the result in a "mirror
view" of the upper diagonal part (what computes your code).
For bigger number of points the difference should be much bigger.
Make your test on a bigger sample of points (say 100 points) and write how
many times faster was my code.

Trying to print multiple text in same line with append method but outputs are different [duplicate]

This question already has answers here:
List of lists changes reflected across sublists unexpectedly
(17 answers)
Closed 3 years ago.
Trying to print possible number combinations in single line as list but the list have wrong output. My output is like this:
[[1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1]]
When it should be like this:
[0, 0, 0]
[0, 0, 1]
[0, 1, 0]
[0, 1, 1]
[1, 0, 0]
[1, 0, 1]
[1, 1, 0]
[1, 1, 1]
My code is
if __name__ == '__main__':
x = 1
y = 1
z = 1
kordinat = ["x","y","z"]
result = []
for xx in range(x+1):
kordinat[0] = xx
for yy in range(y+1):
kordinat[1] = yy
for zz in range(z+1):
kordinat[2]= zz
print(kordinat)
result.append(kordinat)
print(result)
You should take itertools.product():
from itertools import product
result = list(product(range(2), repeat=3))
print(result)
# [(0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1), (1, 0, 0), (1, 0, 1), (1, 1, 0), (1, 1, 1)]
EDIT:
This does not explain, why you end up having a list full of [1, 1, 1] elements. The reason can be found here. Through all your iterations, you work with a list called koordinat. When you append this to your overall list result, you append a reference to the very same object all the time. So you will have a list full of references to the same list koordinat. So changing koordinat to [1, 1, 1] in the last iteration, will change all references in your result list to this value as well. This can best be seen, when you print result after each append()
change this line:
result.append(kordinat)
to
result.append(kordinat.copy())
list is passed or assigned as reference so if you change the value it'll change everywhere.
If you want all the possible combinations of 0,1 of size 3, use combinations from itertools and call it as combinations([0,1],3). This will give you all the possible combinations you are expecting
To print elements of list in new line use pprint as below,
>>> from pprint import pprint as pp
>>> pp(result)
[[1, 1, 1],
[1, 1, 1],
[1, 1, 1],
[1, 1, 1],
[1, 1, 1],
[1, 1, 1],
[1, 1, 1],
[1, 1, 1]]
Edit-1:
Assuming, you are trying to find the binary numbers of the sequence. In your example, it is from 0-7(1-byte or 8-bits).
Try this,
>>> result = [[int(j) for j in "{0:03b}".format(i)] for i in range(8)]
>>> pp(result)
[[0, 0, 0],
[0, 0, 1],
[0, 1, 0],
[0, 1, 1],
[1, 0, 0],
[1, 0, 1],
[1, 1, 0],
[1, 1, 1]]

How to calculate all the combinations of lists

I am blocked on a Python problem and hope someone could help me.
The problem is prety simple actually.
Im trying to build lists with all combination possible but the elements of the list have not the same range.
here is my code, I tried to do something with for loop but it doesnt work.
for j in range(0,size):
for k, val in enumerate(self.Algo.Inputs[j].Values):
self.Commandlist[j] = k
self.Commandlist is a list with fix range, and fill with zero at first.
self.Commandlist = [0,0,0]
self.Algo.Inputs[j].Values gives me the size of each elements, for example, if self.Algo.Inputs[0].Values = 4
self.Algo.Inputs[1].Values = 1
self.Algo.Inputs[2].Values = 2
i want all the combinations, [0,0,0],[1,0,0],[2,0,0],[3,0,0],[4,0,0],[0,1,0],[1,1,0],[2,1,0],[3,1,0],[4,1,0] etc..
I think I forgot a loop but i cant figure out. I tried some stuff with itertools module as well, but i cant make it work.
Thans for your help.
As mentioned you can use itertools, for example like that:
import itertools
a = b = c = range(3) # you can specify different range for each one
[list(x) for x in list(itertools.product(a, b, c))]
Result:
[[0, 0, 0], [0, 0, 1], [0, 0, 2], [0, 1, 0], [0, 1, 1], [0, 1, 2], [0, 2, 0], [0, 2, 1], [0, 2, 2], [1, 0, 0], [1, 0, 1], [1, 0, 2], [1, 1, 0], [1, 1, 1], [1, 1, 2], [1, 2, 0], [1, 2, 1], [1, 2, 2], [2, 0, 0], [2, 0, 1], [2, 0, 2], [2, 1, 0], [2, 1, 1], [2, 1, 2], [2, 2, 0], [2, 2, 1], [2, 2, 2]]

Python: using append within recursive function - overwrites previous elements

Could someone explain how to fix the below? I've read some explanations, but couldn't get my head around it...
Many thanks in advance!
k = 2 # number of possible values for each element, in this case 0 or 1
length = 3 # length of list
result = [0] * length # initialise list
results = []
# generate permutations of list
def permutations(i, k, length):
j = 0
while j < k:
result[i] = j
if i == length - 1:
print("Result: ", result)
results.append(result)
print("Results: ", results)
else:
permutations(i + 1, k, length)
j += 1
permutations(0, k, length)
Below the output. The problem is that all previous elements in the list are overwritten...
Result: [0, 0, 0]
Results: [[0, 0, 0]]
Result: [0, 0, 1]
Results: [[0, 0, 1], [0, 0, 1]]
Result: [0, 1, 0]
Results: [[0, 1, 0], [0, 1, 0], [0, 1, 0]]
Result: [0, 1, 1]
Results: [[0, 1, 1], [0, 1, 1], [0, 1, 1], [0, 1, 1]]
Result: [1, 0, 0]
Results: [[1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0]]
Result: [1, 0, 1]
Results: [[1, 0, 1], [1, 0, 1], [1, 0, 1], [1, 0, 1], [1, 0, 1], [1, 0, 1]]
Result: [1, 1, 0]
Results: [[1, 1, 0], [1, 1, 0], [1, 1, 0], [1, 1, 0], [1, 1, 0], [1, 1, 0], [1, 1, 0]]
Result: [1, 1, 1]
Results: [[1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1]]
You are appending the same list everytime. Modifying the list via that reference will propagate changes to every where the list object lives; it is the same list.
You should append a shallow copy instead, so the reference result only modifies the current list:
...
results.append(result[:])
Otherwise, you could create a new list object at the start of the function so each recursive call gets its own list:
def permutations(i, k, length):
result = []
...
I believe changing results.append(result) to result.append(result[:]) should fix the problem. It is because of the mutability of lists
What you implement can be described as repeated permutations or cartesian product.
There are k ** length lists or tuples that can be generated this way.
As with any combination, permutation or product, itertools can help you :
from itertools import product
k = 2 # number of possible values for each element, in this case 0 or 1
length = 3 # length of list
print(list(product(range(k), repeat=length)))
#[(0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1), (1, 0, 0), (1, 0, 1), (1, 1, 0), (1, 1, 1)]
Done!

How can I count duplicates in a nested list based on first two elements in python

I have a list in the form:
lst = [[1, 0, 0, 0], [1, 1, 0, 0], [2, 0, 0, 0], [2, 1, 0, 0], [2, 1, 0, 0], [1, 1, 0, 0], [3, 1, 0, 0], [1, 3, 0, 0], [2, 1, 0, 0], [2, 0, 0, 0]]
However the last two sub-elements will always be zero at the start so it could be like:
lst = [[1, 0], [1, 1], [2, 0], [2, 1], [2, 1], [1, 1], [3, 1], [1, 3], [2, 1], [2, 0]]
If that is easier.
What I want is to remove and count the duplicates of this list and set the 3rd sub-element to the count so if we take the above I want:
lst = [[1, 0, 1, 0], [1, 1, 2, 0], [2, 0, 2, 0], [2, 1, 3, 0], [3, 1, 1, 0], [1, 3, 1, 0]]
I have found explanations of how to remove duplicates at:
Removing Duplicates from Nested List Based on First 2 Elements
and
Removing duplicates from list of lists in Python
but I don't know how to count the duplicates. The order of the elements in the overall list doesn't matter but the order of the elements in the sub-lists must be preserved as [1,3] and [3,1] aren't the same thing.
If this turns out to be a dead end I could do something like hash the first two elements for counting but only if I could get them back after counting.
Any help is appreciated.
Sorry for dyslexia!
For example:
lst = [[1, 0, 0, 0], [1, 1, 0, 0], [2, 0, 0, 0], [2, 1, 0, 0], [2, 1, 0, 0], [1, 1, 0, 0], [3, 1, 0, 0], [1, 3, 0, 0], [2, 1, 0, 0], [2, 0, 0, 0]]
from collections import Counter
c = Counter(tuple(i) for i in lst)
print [list(item[0][0:2] + (item[1], 0)) for item in c.items()]
# [[1, 0, 1, 0], [1, 1, 2, 0], [3, 1, 1, 0], [2, 1, 3, 0], [1, 3, 1, 0], [2, 0, 2, 0]]
To elaborate on the great hint provided by njzk2:
Turn your list of lists into a list of tuples
Create a Counter from it
Get a dict from the Counter
Set the 3rd element of the sublists to the frequency from the Counter
from collections import Counter
lst = [[1, 0, 0, 0], [1, 1, 0, 0], [2, 0, 0, 0], [2, 1, 0, 0], [2, 1, 0, 0], [1, 1, 0, 0], [3, 1, 0, 0], [1, 3, 0, 0], [2, 1, 0, 0], [2, 0, 0, 0]]
list_of_tuples = [tuple(elem) for elem in lst]
dct = dict(Counter(list_of_tuples))
lst = [list(e) for e in dct]
for elem in lst:
elem[2] = dct[tuple(elem)]
Edit: removed duplicates with the line before the for loop. Didn't see that requirement before.
You can do this to keep count of the duplicates:
lst = [[1, 0], [1, 1], [2, 0], [2, 1], [2, 1], [1, 1], [3, 1], [1, 3], [2, 1], [2, 0]]
for x in lst:
count = 1
tmpLst = list(lst)
tmpLst.remove(x)
for y in tmpLst:
if x[0] == y[0] and x[1] == y[1]:
count = count + 1
x.append(count)
#x.append(0) #if you want to add that 4th element
print lst
Result:
[[1, 0, 1], [1, 1, 2], [2, 0, 2], [2, 1, 3], [2, 1, 3], [1, 1, 2], [3, 1, 1], [1, 3, 1], [2, 1, 3], [2, 0, 2]]
Then you can take lst and remove duplicates as mentioned in the link you posted.
A different (maybe functional) approach.
lst = [[1, 0, 0, 0], [1, 1, 0, 0], [2, 0, 0, 0], [2, 1, 0, 0],\
[2, 1, 0, 0], [1, 1, 0, 0], [3, 1, 0, 0], [1, 3, 0, 0],\
[2, 1, 0, 0], [2, 0, 0, 0]]
def rec_counter(lst):
# Inner method that is called at the end. Receives a
# list, the current element to be compared and an accumulator
# that will contain the result.
def counter(lst, elem, acc):
new_lst = [x for x in lst if x != elem]
elem[2] = lst.count(elem)
acc.append(elem)
if len(new_lst) == 0:
return acc
else:
return counter(new_lst, new_lst[0], acc)
# This part starts the recursion of the inner method. If the list
# is empty, nothing to do. Otherwise, count starting with the first
# element of the list and an empty accumulator.
if len(lst) == 0:
return []
else:
return counter(lst, lst[0], [])
print rec_counter(lst)
# [[1, 0, 1, 0], [1, 1, 2, 0], [2, 0, 2, 0], \
# [2, 1, 3, 0], [3, 1, 1, 0], [1, 3, 1, 0]]

Categories