Randomly generating different list from list - python

first I created a list called “citys” then it tried to swap randomly two elements in the “citys” list for 5 times and at the same time tried to store the new lists in the “number_of_citys” but it turns out bad every time it loops, it insert the last swapped arrays only.
I used this randomly generated list ,
citys= [[1,2], [3,4],[1,3],[5,2]] , to create another list. And I expected my list to be,
orders_of_citys=[[[1,2], [5,2],[1,3][3,4]] , [[5,2], [1,2],[1,3][3,4]],[ [1,3], [1,2],[5,2][3,4]], [[3,4], [1,2],[5,2][1,3]], [1,3], [1,2],[5,2][3,4]] ]
but I got the following
order_of_citys =[[[1,3], [1,2],[5,2][3,4]], [1,3], [1,2],[5,2][3,4]], [1,3], [1,2],[5,2][3,4]] ,[1,3], [1,2],[5,2][3,4]], [1,3], [1,2],[5,2][3,4]]]
I have used append(), +=, and insert built in function and operators but I still get the same array. please I would like some one to point me my problem.The code I wrote is the following.
import random
citys = []
number_of_cities = 5
orders_of_citys = []
pop = 5
#give random place for cities on 2D plane
for i in range(number_of_cities):
citys.append( [ random.randint(0, 1000), random.randint(0, 1000)])
#suffle points (citys) position to get different path
def swap(c, a, b):
value = c[a]
c[a] = c[b]
c[b] = value
return c
for j in range(pop):
a = random.randint(0, len(citys)-1)
b= random.randint(0, len(citys)-1)
new_path = swap(citys, a, b)
orders_of_citys.append(new_path)
Thanks!

Your swap function is literally modifying the array, not returning a new array. So orders_of_citys contains five copies of the exact same array, and any time you. modify one of those arrays using swap, you're modifying all of them.
If you really want to see what's going on, change the last line to be
orders_of_citys.append(new_path[:])
which makes a copy of the array and then appends it to the variable.

The new_path is actually a reference to citys, and you append the reference. Once the citys is changed, all the referred data will be changed too, so it have the same data.
And the solution is to make a deep copy of the array and append the copy.
from copy import deepcopy
# Other codes
def swap(c, a, b):
d = deepcopy(c)
value = d[a]
d[a] = d[b]
d[b] = value
return d
The solution above is more easier. I'm late QwQ

Related

Averaging results from a list of lists where every nth list is a reptition

So I wrote a model that computes results over various parameters via a nested loop. Each computation returns a list of len(columns) = 10 elements, which is added to a list of lists (res).
Say I compute my results for some parameters len(alpha) = 2, len(gamma) = 2, rep = 3, where rep is the number of repetitions that I run. This yields results in the form of a list of lists like this:
res = [ [elem_1, ..., elem_10], ..., [elem_1, ..., elem_10] ]
I know that len(res) = len(alpha) * len(gamma) * repetitions = 12 and that each inner list has len(columns) = 10 elements. I also know that every 3rd list in res is going to be a repetition (which I know from the way I set up my nested loops to iterate over all parameter combinations, in fact I am using itertools).
I now want to average the result list of lists. What I need to do is to take every (len(res) // repetitions) = 4th list , add them together element-wise, and divide by the number of repetitions (3). Sounded easier than done, for me.
Here is my ugly attempt to do so:
# create a list of lists of lists, where the inner list of lists are lists of the runs with the identical parameters alpha and gamma
res = [res[i::(len(res)//rep)] for i in range(len(res)//rep)]
avg_res = []
for i in res:
result = []
for j in (zip(*i)):
result.append(sum(j))
avg_res.append([i/repetitions for i in result])
print(len(result_list), avg_res)
This actually yields, what I want, but it surely is not the pythonic way to do it. Ugly as hell and 5 minutes later I can hardly make sense of my own code...
What would be the most pythonic way to do it? Thanks in advance!
In some cases a pythonic code is a matter of style, one of its idioms is using list comprehension instead of loop so writing result = [sum(j) for j in (zip(*i))] is simpler than iterating over zip(*i).
On the other hand nested list comprehension looks more complex so don't do
avg_res = [[i/repetitions for i in [sum(j) for j in (zip(*j))]] for j in res]
You can write:
res = [res[i::(len(res)//rep)] for i in range(len(res)//rep)]
avg_res = []
for i in res:
result = [sum(j) for j in (zip(*i))]
avg_res.append([i/repetitions for i in result])
print(len(result_list), avg_res)
Another idiom in Programming in general (and in python in particular) is naming operations with functions, and variable names, to make the code more readable:
def sum_columns(list_of_rows):
return [sum(col) for col in (zip(*list_of_rows))]
def align_alpha_and_gamma(res):
return [res[i::(len(res)//rep)] for i in range(len(res)//rep)]
aligned_lists = align_alpha_and_gamma(res)
avg_res = []
for aligned_list in aligned_lists:
sums_of_column= sum_columns(aligned_list)
avg_res.append([sum_of_column/repetitions for sum_of_column in sums_of_column])
print(len(result_list), avg_res)
Off course you can choose better names according to what you want to do in the code.
It was a bit hard to follow your instructions, but as I caught, you attempt to try sum over all element in N'th list and divide it by repetitions.
res = [list(range(i,i+10)) for i in range(10)]
N = 4
repetitions = 3
average_of_Nth_lists = sum([num for iter,item in enumerate(res) for num in item if iter%N==0])/repetitions
print(average_of_Nth_lists)
output:
85.0
explanation for the result: equals to sum(0-9)+sum(4-13)+sum(8-17) = 255 --> 255/3=85.0
created res as a list of lists, iterate over N'th list (in my case, 1,5,9 you can transform it to 4,8 etc if that what you are wish, find out where in the code or ask for help if you don't get it), sum them up and divide by repetitions

varying degree of shuffling using random module python

I am using two architecture programs, with visual programming plugins (Grasshopper for Rhino and Dynamo for Revit - for those that know / are interested)
Grasshopper contains a function called 'Jitter' this will shuffle a list, however it has an input from 0.0 to 1.0 which controls the degree of shuffling - 0.0 results in no shuffling 1.0 produces a complete shuffle.
The second of the programs (Dynamo) does not contain this functionality. It contains a shuffle module (which contains a seed value) however it is a complete random shuffle.
Ultimately the goal is to produce a series of solid and glazed panels, but to produce a slight random effect (but avoiding large clumping of solid and glazed elements - hence I want a "light shuffle")
I have written a code which will calculate the number of glazed(True) and solid(False) values required and then evenly distribute True and False values based on the number of items and percent specified.
I have checked out the random module reference however I'm not familiar with the various distributions as described.
Could someone help out or point me in the right direction if an existing function would achieve this.
(I have cheated slightly by adding True False alternately to make up the correct number of items within the list - list3 is the final list, list2 contains the repeated module of true falses)
Many thanks
import math
import random
percent = 30
items = 42
def remainder():
remain = items % len(list2)
list3.append(True)
remain -= 1
while remain > 0 :
list3.append(False)
remain -= 1
return list3
#find module of repeating True and False values
list1 = ([True] + [False] * int((100/percent)-1))
#multiply this list to nearest multiple based on len(items)
list2 = list1 * int(items/(100/percent))
# make a copy of list2
list3 = list2[:]
#add alternating true and false to match len(list3) to len(items)
remainder()
#an example of a completely shuffled list - which is not desired
shuffled = random.sample(list3, k = len(list3))
Here is an approach based on this paper which proves a result about the mixing time needed to scramble a list by using swaps of adjacent items
from random import choice
from math import log
def jitter(items,percent):
n = len(items)
m = (n**2 * log(n))
items = items[:]
indices = list(range(n-1))
for i in range(int(percent*m)):
j = choice(indices)
items[j],items[j+1] = items[j+1],items[j]
return items
A test, each line showing the result of jitter with various percents being applied to the same list:
ls = list(('0'*20 + '1'*20)*2)
for i in range(11):
p = i/10.0
print(''.join(jitter(ls,p)))
Typical output:
00000000000000000000111111111111111111110000000000000000000011111111111111111111
00000000000000111100001101111011011111001010000100010001101000110110111111111111
00000000100100000101111110000110111101000001110001101001010101100011111111111110
00000001010010011011000100111010101100001111011100100000111010110111011001011111
00100001100000001101010000011010011011111011001100000111011011111011010101011101
00000000011101000110000110000010011001010110011111100100111101111011101100111110
00110000000001011001000010110011111101001111001001100101010011010111111011101100
01101100000100100110000011011000001101111111010100000100000110111011110011011111
01100010110100010100010100011000000001000101100011111011111011111011010100011111
10011100101000100010001100100000100111001111011011000100101101101010101101011111
10000000001000111101101011000011010010110011010101110011010100101101011110101110
I'm not sure how principled the above is, but it seems like a reasonable place to start.
There's no clear definition of what "degree of shuffling" (d) means, so you'll need to choose one. One option would be: "the fraction of items remaining unshuffled is (1-d)".
You could implement that as:
Produce a list of indices
Remove (1-d)*N of them
Shuffle the rest
Reinsert the ones removed
Use these to look up values from the original data
def partial_shuffle(x, d):
"""
x: data to shuffle
d: fraction of data to leave unshuffled
"""
n = len(x)
dn = int(d*n)
indices = list(range(n))
random.shuffle(indices)
ind_fixed, ind_shuff = indices[dn:], indices[:dn]
# copy across the fixed values
result = x[:]
# shuffle the shuffled values
for src, dest in zip(ind_shuff, sorted(ind_shuff)):
result[dest] = x[src]
return result
The other algorithms you're referring to are probably using the Fisher-Yates shuffle under the hood.
This O(n) shuffle starts with the first element of an array and swaps it with a random higher element, then swaps the second element with a random higher element, and so on.
Naturally, stopping this shuffle before you reach the last element at some fraction [0,1] would give a partially-randomized array, like you want.
Unfortunately, the effect of the foregoing is that all the "randomness" builds up on one side of the array.
Therefore, make a list of array indices, shuffle these completely, and then use the indices as an input to the Fisher-Yates algorithm to partially sort the original array.
I believe I found a more versatile, robust, and a consistent way to implement this "adjustable shuffling" technique.
import random
import numpy as np
def acc_shuffle(lis, sr, array=False, exc=None): # "sr" = shuffling rate
if type(lis) != list: # Make it compatible with shuffling (mxn) numpy.ndarrays
arr = lis
shape = arr.shape
lis = list(arr.reshape(-1))
lis = lis[:] # Done, such that any changes applied on "lis" wont affect original input list "x"
indices = list(range(len(lis)))
if exc is not None: # Exclude any indices if necessary
for ele in sorted(exc, reverse=True):
del indices[ele]
shuff_range = int(sr * len(lis) / 2) # How much to shuffle (depends on shuffling rate)
if shuff_range < 1:
shuff_range = 1 # "At least one shuffle (swap 2 elements)"
for _ in range(shuff_range):
i = random.choice(indices)
indices.remove(i) # You can opt not to remove the indices for more flexibility
j = random.choice(indices)
indices.remove(j)
temp = lis[i]
lis[i] = lis[j]
lis[j] = temp
if array is True:
return np.array(lis).reshape(shape)
return lis

Filling a list inside a for loop in python

I am trying to make a vector out of two different ones as shown in the piece of code below.
However, I get a list out of range exception on the 5th line the first time the code goes in the for loop.
What am I doing wrong?
def get_two_dimensional_vector(speeds, directions):
vector = []
for i in range(10):
if (i % 2 == 0):
vector[i/2][0] = speeds[i/2]
else :
vector[i/2 - 1/2][1] = directions[i/2 - 1/2]
You can't use a Python list this way. It's not like a C array with a
predefined length. If you want to add a new element, you have to use the
append method or something.
Aside from that, you're also using a second index, implying that the
elements of vector are themselves lists or dicts or something, before
they've even been assigned.
It looks like you want to convert speeds and directions to a
two-dimensional list. So, first, here's how to do that with a loop. Note
that I've removed the fixed-size assumption you were using, though the
code still assumes that speeds and directions are the same size.
def get_two_dimensional_vector(speeds, directions):
vector = []
for i in range(len(speeds)):
vector.append([speeds[i], directions[i]])
return vector
speeds = [1, 2, 3]
directions = [4, 5, 6]
v = get_two_dimensional_vector(speeds, directions)
print(v)
Now, the Pythonic way to do it.
print(zip(speeds, directions))

Obtaining the first and second "column's" from a pair of lists

I have many pairs of lists of variable lengths (5,4,6 pairs etc..) inside a single big list, lets call it LIST. Here are two lists among the many inside the big LIST as an example:
[(38.621833, -10.825707),
(38.572191, -10.84311), -----> LIST[0]
(38.580202, -10.860877),
(38.610917, -10.85217),
(38.631526, -10.839338)]
[(38.28152, -10.744559),
(38.246368, -10.744552), -----> LIST[1]
(38.246358, -10.779088),
(38.281515, -10.779096)]
I need to create two seperate variables lets say, of which one variable will have the first "column" (i.e. LIST[0][0][0], LIST[0][1][0] AND SO ON) of all the pairs of the lists(i.e. 38.621833, 38.572191 etc) and the second variable will have the second "column" (i.e. LIST[0][0][1], LIST[0][1][1] AND SO ON) of all the pairs of the lists.
So finally I will have two variables (say x,y) that will contain all the values of the first and second "columns" of all the lists in the LIST.
The problem I face is that all these lists are not of the same length!!
I tried
x = []
y = []
for i in range(len(LIST)):
x.append(LIST[i][0][0]) #append all the values of the first numbers
y.append(LIST[i][1][1]) #append all the values of the second numbers
What I expect:
x = (38.621833,38.572191,38.580202,38.610917,38.631526,38.28152,38.246368,38.246358,38.281515)
y = (-10.825707,-10.84311,-10.860877,-10.85217,-10.839338,-10.744559,-10.744552,-10.779088,-10.779096)
But here because of the variable pairs, my loop stops abrubptly in between.
I know I need to also change the LIST[i][j][0] here, and j changes with each list. But because of the different pairs, I don't know how to go about.
How do I go about doing this?
I would use two simple for loops (it's also generic for LIST being longer than 2):
x=[]
y=[]
for i in range(len(LIST)):
for j in LIST[i]:
x.append(j[0])
y.append(j[1])
You should transpose the sublists and use itertool.chain to create a single list:
from itertools import chain
zipped = [zip(*x) for x in l]
x, y = chain.from_iterable(ele[0] for ele in zipped),chain.from_iterable(ele[1] for ele in zipped)
print(list(x),list(y))
[38.621833, 38.572191, 38.580202, 38.610917, 38.631526, 38.28152, 38.246368, 38.246358, 38.281515] [-10.825707, -10.84311, -10.860877, -10.85217, -10.839338, -10.744559, -10.744552, -10.779088, -10.779096]
for ele1,ele2 in zip(x,y):
print(ele1,ele2)
38.621833 -10.825707
38.572191 -10.84311
38.580202 -10.860877
38.610917 -10.85217
38.631526 -10.839338
38.28152 -10.744559
38.246368 -10.744552
38.246358 -10.779088
38.281515 -10.779096
Here you go. tuple as requested.
my = [(38.621833, -10.825707),(38.572191, -10.84311),(38.580202, -10.860877),(38.610917, -10.85217),(38.631526, -10.839338)]
my1 = [(38.28152, -10.744559),(38.246368, -10.744552),(38.246358, -10.779088),(38.281515, -10.779096)]
l1 = map(tuple,zip(*my))[0]
l2 = map(tuple,zip(*my))[1]
print l1,l2
Output:
(38.621833, 38.572191, 38.580202, 38.610917, 38.631526)(-10.825707, -10.84311, -10.860877, -10.85217, -10.839338)
Use map function with zip and * stuple operator.
l = [(38.621833, -10.825707),
(38.572191, -10.84311),
(38.580202, -10.860877),
(38.610917, -10.85217),
(38.631526, -10.839338)]
x= map(list, zip(*l))[0]
y = map(list, zip(*l))[1]
print 'x = {},\n y = {}' .format(x,y)
x = [38.621833, 38.572191, 38.580202, 38.610917, 38.631526],
y = [-10.825707, -10.84311, -10.860877, -10.85217, -10.839338]
or if you don't want to store it in variables then d0n't use indexing in above solution,
map(list, zip(*l)) # will give you a nested list
Your LIST extends out of 2 lists.
With
for i in range(len(LIST)):
you run exactly 2 times through your loop.
If you want to solve your problem with for-loops your need to nest them:
#declare x, y as lists
x = []
y = []
for i_list in LIST:
#outer for-loop runs 2 times - one for each list appended to LIST.
#1st run: i_list becomes LIST[0]
#2nd run: i_list becomes LIST[1]
for touple in i_list:
#inner for-loop runs as often as the number of tuple appended to i_list
#touple becomes the content of i_list[#run]
x.append(touple[0]) #adds x-value to x
y.append(touple[1]) #adds y-value to y
If you prefer working with indexes use:
for i in range(len(LIST)):
for j in range(len(LIST[i])):
x.append(LIST[i][j][0])
y.append(LIST[i][j][1]])
NOT working with indexes for appending x- or y-values is much easier to write (saves complex thoughts about the List-Structure and correct using of indexes) and is much more comprehensible for extern people reading your code.

Shuffling a list

in this program I'm trying to shuffle a list by randomly choosing two items from a list and swapping them round, and then repeating this process several times.
The problem I have encountered is I don't know how I can swap the items round and print the shuffled list.
For instance if my two random values were a and b, if I were to just put:
a = b
b = a
then that would change the value of a to b, but when it tries to change b to a, no change would occur as a has already been changed to b.
The only way I can think that this would work is swapping them at the same time, but I do not know of a function/ way to swap them round.
Also if a, b were items of a list L, after I swapped them round if I used
print L
should it print the altered version? I only ask because from what I have tried it is not doing that.
NB I am trying to shuffle this list stage by stage by swapping, instead of using the shuffle function imported from random.
In Python, you can swap two variables like this:
a, b = b, a
This is called multiple assignment, you can find more information about it here.
In other languages this is usually done by assigning a temporary variable:
tmp = a
a = b
b = tmp
Isn't Python great?
The random.shuffle function uses swapping too. It would be worthwhile to look at its source code:
def shuffle(self, x, random=None, int=int):
"""x, random=random.random -> shuffle list x in place; return None.
Optional arg random is a 0-argument function returning a random
float in [0.0, 1.0); by default, the standard random.random.
"""
if random is None:
random = self.random
for i in reversed(xrange(1, len(x))):
# pick an element in x[:i+1] with which to exchange x[i]
j = int(random() * (i+1))
x[i], x[j] = x[j], x[i]
Observe how the last line performs a swap using tuple packing and unpacking.
As an alternative to packing and unpacking, the traditional way to swap variables is to use a temporary variable:
t = x[i]
x[i] = x[j]
x[j] = t
Use a temp variable for your first problem:
temp = a
a = b
b = temp
In Python you can also do this:
a, b = b, a
I suspect your second problem is because you're changing things you got out of the list, instead of changing the list. Try this:
i, j = # two indexes to swap in the list
L[i], L[j] = L[j], L[i]
Use a temporary variable:
temp = a
a = b
b = temp
http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
Just swapping items is known to be bad.
Don't forget that if you have n items, there are n! arrangements. If your random number is 32 bits, there are 2^32 numbers.
It's hard then to shuffle a pack of cards with a 32 bit number as 52! is very much bigger than 2^32

Categories

Resources