How can I shuffle a list with no repetition? - python

array1=[3, 7, 11, 12, 15, 5, 1, 4]
array2=[14, 10, 9, 16, 2, 13, 6, 8]
I shuffled these arrays.
shuffled1 = sorted(array1, key=lambda k: random.random())
shuffled2 = sorted(array2, key=lambda k: random.random())
However, I do not want the same numbers to come to the same indexes again. For example: 3 and 14 at index 0, 7 and 10 at index 1. I don't want these numbers to be reciprocal again. All numbers need to be couple with another number.
For example:
shuffled1 =[1, 15, 4, 12, 7, 5, 3, 11]
shuffled2 =[13, 8, 9, 14, 2, 16, 6, 10]
İf shuffled arrays not like this, shuffle again.

As first step you can create a dictionary that will be used if shuffled lists array1 and array2 don't contain the values from initial state. Then we repeat shuffling until the condition is met.
For example:
from random import random
array1=[3, 7, 11, 12, 15, 5, 1, 4]
array2=[14, 10, 9, 16, 2, 13, 6, 8]
disallowed_dict = {}
for a, b in zip(array1, array2):
disallowed_dict.setdefault(a, []).append(b)
while any(b in disallowed_dict[a] for a, b in zip(array1, array2)):
array1 = sorted(array1, key=lambda _: random())
array2 = sorted(array2, key=lambda _: random())
print(array1)
print(array2)
Prints (for example):
[1, 15, 4, 7, 5, 11, 12, 3]
[16, 6, 10, 13, 8, 14, 9, 2]

I had completely missread the condition. Try this:
import numpy as np
from random import randint
array1=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
def my_shuffle(array1, array2):
narray1 = np.array(array1)
idxs = []
for element in array1:
idx = randint(0,len(array1)-1)
while idx in idxs:
idx = randint(0,len(array1)-1)
idxs.append(idx)
narray1[idx] = element
narray2 = np.array(array2)
it = 0
idxs2 = []
for element in array2:
idx = randint(0,len(array2)-1)
while idx in idxs2 or idx == idxs[it]:
idx = randint(0,len(array2)-1)
idxs2.append(idx)
it+=1
narray2[idx] = element
return narray1, narray2
new1, new2 = my_shuffle(array1, array1)
print(f"{new1}\n{new2}")

Related

How to divide a list or array into the correct number of groups

I have tried two methods of creating groups of numbers and then dividing those groups into smaller groups of sequential numbers and selecting one.
The first method used lists, but they wouldn't divide the groups correctly.
# This program prints the wrong number of elements.
# I need the correct number of elements, and I want the list to
# deal with floats.
begin = 1
end = 22
num_groop = 2
num_in_groop = (begin + end) // num_groop
lis = []
# loop iterates through index making list from beginning to end
end = num_in_groop
for _ in np.arange(num_groop):
lis.append(list(np.arange(begin, end+1)))
begin += num_in_groop
end += num_in_groop
print('lis', lis,)
# a function to choose one group from the lis and print it
x_1 = lis[0]
x_2 = lis[1]
inp = input('Choose group 1 or 2 by entering 1 or 2\n')
intinp = int(inp)
def choosefunc():
if intinp == 1:
del x_2[:]
print('You chose group x_1 = ',x_1[:])
elif intinp == 2:
del x_1[:]
print('You chose group x_2 = ',x_2[:])
choosefunc()
print('lis is now', lis)
The problem with this is that when it's repeated to narrow down the groups, it divides only using integers. Though the original max number was 22, after repeating this twice, it produces the wrong number of lists. To be correct maths, it should be this:
The first division of the list into an even number is fine:
[[1,2,3,4,5,6,7,8,9,10,11], [12,13,14,15,16,17,18,19,20,21,22]].
Then when choosing one of these groups, choose the first, and divide by two again that's where the maths doesn't work. It should be this:
lis [[1, 2, 3, 4, 5, 5.5], [5.6, 7, 8, 9, 10, 11]]
But because it doesn't seem to handle floats, it is this:
lis [[1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12]].
That's not correct maths. 22/2 = 11, and 11/2 = 5.5.
I want the lists to be of equal size.
# ---------------------------------------------------
When I try to solve the problem using lists, by using numpy arrays, I get an error that stops me from continuing.
# I tried to solve this problem using array but getting an error.
# TypeError: 'tuple' object cannot be interpreted as an integer.
import numpy as np
begin = 1
end = 22
num_groop = 2
num_in_groop = (begin + end) // num_groop
lis = np.array([])
print('lis is now', lis) # prints the new value for lis
end = num_in_groop
for _ in np.arange(num_groop):
print('line20, lis now', lis)
lis(np.arange(range((begin, end+1)))) #error
begin += num_in_groop
end += num_in_groop
print('lis', lis)
If [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10, 11]] is an acceptable split, then
def subdivide_list(a):
midpoint = len(a) // 2
return a[:midpoint], a[midpoint:]
lists = [list(range(1, 12))]
for x in range(3):
print(x, lists)
new_lists = []
for a in lists:
new_lists.extend(subdivide_list(a))
lists = new_lists
does what you want:
0 [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]]
1 [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10, 11]]
2 [[1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11]]
EDIT
This also works for [list(range(1, 23))] (print adjusted to show the lengths of the lists):
0 [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22]] [22]
1 [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], [12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22]] [11, 11]
2 [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10, 11], [12, 13, 14, 15, 16], [17, 18, 19, 20, 21, 22]] [5, 6, 5, 6]

Replace values in a list if condition is true

how can I replace the numbers that are greater than 9 by their sum of digits?
right now the list multipliedlist =
[1, 4, 3, 8, 5, 12, 7, 16, 2]
I need to change it to (ex, num 12 and num 16 replaced to (3) and (7) )
[1, 4, 3, 8, 5, 3, 7, 7, 2]
I can use sum(map(int, str(number))) to add the digits but how can i change the values in the same list by their index?
def check_id_valid(id_number):
updatedid = map(int, str(id_number))
multipliedlist = [i * 1 if j % 2 == 0 else i * 2 for j, i in enumerate(updatedid)]
# for index, number in enumerate(multipliedlist):
# if multipliedlist[index] > 9:
# multipliedlist[index] = sum(map(int, str(number)))
# else:
# multipliedlist[index] == number #statement has no effect error.
print(check_id_valid(123456782))
New to python sorry if this is not explained as it's supposed to be
I appreciate any help,Thanks :)
Using a list comprehension
Ex:
data = [1, 4, 3, 8, 5, 12, 7, 16, 2]
print([sum(map(int, str(i))) if i > 9 else i for i in data])
Output:
[1, 4, 3, 8, 5, 3, 7, 7, 2]
Break your task into the constituent parts, namely
replacing a number with the sum of its digits
doing that for a list of numbers.
def sum_digits(number):
# Convert the number into a string (10 -> "10"),
# iterate over its characters to convert each of them
# back to an integer, then use the `sum()` builtin for
# summing.
return sum(int(digit_char) for digit_char in str(number))
def sum_all_digits(numbers):
return [sum_digits(number) for number in numbers]
print(sum_all_digits([1, 4, 3, 8, 5, 12, 7, 16, 2]))
outputs the expected
[1, 4, 3, 8, 5, 3, 7, 7, 2]
To change values by index you can use enumerate() function:
def sum_digits(n):
r = 0
while n:
r, n = r + n % 10, n // 10
return r
multipliedlist = [1, 4, 3, 8, 5, 12, 7, 16, 2]
for i, n in enumerate(multipliedlist):
multipliedlist[i] = sum_digits(multipliedlist[i])
print(multipliedlist)
[1, 4, 3, 8, 5, 3, 7, 7, 2]

How do you add adjacent numbers in a list? I can't get the last variable

Let x = [3, 8, -2, 6, 9, -4, 7, 1, -5, 8]
Use a for loop to add adjacent elements in x.
Store each of these results in a vector, sa.
Display both the vector x and the vector sa.
For example, the first 3 numbers of sa will be:
sa = [11, 9, 12, …] = [(3+8), (3+8+(-2)), (8+(-2)+6), …]
I have something like this...
x = [3, 8, -2, 6, 9, -4, 7, 1, -5, 8]
sa = []
for i in range (0, len(x)-1):
if i<1:
sa.append(x[0] + x[1])
elif i >= 1 & i< len(x):
sa.append(x[i-1] + x[i] + x[i+1])
if i == 0:
sa.append(x[i] + x[i+1])
print("Here is sa", sa)
but I can't get the last variable of -5 +8 to appear please help
what I end up getting is
Here is sa, [11, 11, 9, 12, 13, 11, 12, 4, 3, 4]
but I also need the last value it should be (-5+8)= 3 so the total final answer should include the three like
[11, 11, 9, 12, 13, 11, 12, 4, 3, 4, 3]
or even
[11, 9, 12, 13, 11, 12, 4, 3, 4, 3]
You can write this as a list comprehension, noting the ith element in sa is the sum of the x values from x[i-1] to x[i+1]. Now those indexes may overrun the boundaries of x, so we need to use max and min to keep them in range:
x = [3, 8, -2, 6, 9, -4, 7, 1, -5, 8]
sa = [sum(x[max(i-1, 0):min(i+2, len(x))]) for i in range(len(x))]
print(sa)
Output:
[11, 9, 12, 13, 11, 12, 4, 3, 4, 3]
Just in case if you are looking for non comprehensive way, here it is.
for i in range(len(x)):
if i == 0:
sa.append(x[i] + x[i+1])
elif 1 <= i < len(x)-1:
sa.append(x[i-1] + x[i] + x[i+1])
else:
sa.append(x[i] + x[i-1])
print("Here is sa", sa)
Output:
Here is sa [11, 9, 12, 13, 11, 12, 4, 3, 4, 3]
Your code has some mistakes:
x = [3, 8, -2, 6, 9, -4, 7, 1, -5, 8]
sa = []
# the last element of the loop will be x[len(x)-2], it is -5 in this case
# -5 is the last element this loop process, it adds up 1, -5 and 8
# this loop will not take 8 as the central number, so the results miss the last value
for i in range (0, len(x)-1):
if i<1:
sa.append(x[0] + x[1])
# in python, it is `and` not &, & is bitwise and.
elif i >= 1 & i< len(x):
sa.append(x[i-1] + x[i] + x[i+1])
if i == 0: # this is meaningless, i == 0 is covered in the first if branch
sa.append(x[i] + x[i+1])
print("Here is sa", sa)
Fix your code:
x = [3, 8, -2, 6, 9, -4, 7, 1, -5, 8]
sa = []
# fix one: loop to the last element
for i in range (0, len(x)):
if i<1:
sa.append(x[0] + x[1])
# fix two: do not include the last element in this elif branch
elif i >= 1 and i < len(x) - 1:
sa.append(x[i-1] + x[i] + x[i+1])
# fix three: process the last element.
else:
sa.append(x[i - 1] + x[i])
print("Here is sa", sa)
output:
Here is sa [11, 9, 12, 13, 11, 12, 4, 3, 4, 3]
>>> x = [3, 8, -2, 6, 9, -4, 7, 1, -5, 8]
Create a list with the sum of the first two elements,
>>> q = [sum(x[:2])]
Iterate over the list three at a time and append the sums.
>>> for thing in zip(x,x[1:],x[2:]):
... q.append(sum(thing))
Append the sum of the last two items.
>>> q.append(sum(x[-2:]))
>>> q
[11, 9, 12, 13, 11, 12, 4, 3, 4, 3]

python: how to strip lines efficiently from a matrix, which have elements appearing in other lines

list = [0, 1, 2, 3, 4, 1, 5, 0, 6, 5, 7, 8, 9, 10, 11, 12, 13, 2]
list is used "matrix like"
1. 0 1 2
2. 3 4 1
3. 5 0 6
... and so on. I would like to write all those lines into a new list/matrix, but without lines, that would repeat a number. However the order of a line has to be preserved.
So far I use this:
compa = [0,1,2,3,4,1,5,0,6,5,7,8,9,10,11,12,13,2] #the list to be used as base
temp = [0,1,2] #new list starts from the first element
temp2 = [12,13,2] #new list starts from the last element
Mischzahl = 3 #defines the number of elements in a line of the "matrix"
n = 0
while n < len(compa):
for m in range(0,len(temp)):
if temp[m] == compa[n]:
n = (int(n/Mischzahl) + 1) * Mischzahl - 1 #calculates the "foul" line and sets n to the next line
break
if (n + 1) % Mischzahl == 0 and m == len(temp) - 1 : #if the end of temp is reached, the current line is transferred to temp.
for p in range(Mischzahl):
temp.append(compa[Mischzahl*int(n/Mischzahl) + p])
n += 1
and the same backwards
n = len(compa) - 1
while n > 0: #same as above but starting from last element
for m in range(len(temp2)):
if temp2[m] == compa[n]:
n = (int(n/Mischzahl) - 1) * Mischzahl + Mischzahl
break
if (n) % Mischzahl == 0 and m == len(temp2) - 1:
for p in range(Mischzahl):
temp2.append(compa[Mischzahl*int(n/Mischzahl) + p])
n = n - 1
resulting output for temp and temp2:
[0, 1, 2, 3, 4, 1, 5, 0, 6, 5, 7, 8, 9, 10, 11, 12, 13, 2] #compa
[0, 1, 2, 5, 7, 8, 9, 10, 11] #temp
[12, 13, 2, 9, 10, 11, 5, 7, 8, 3, 4, 1] #temp2
Since this is the most time-consuming part of the script: Is there a more efficient way to do this? Any helpful advice or direction would be highly welcome.
You can define a function that iterates over the list in strides of a given length (in your case 3), checks if the elements of the stride are in a set of numbers, if not extend the out list and update the set.
from math import ceil
def unique_by_row(compa, stride_size=3, reverse=False):
strides = ceil(len(compa)/stride_size)
out = []
check = set()
it = range(strides)
if reverse:
it = reversed(it)
for i in it:
x = compa[stride_size*i:stride_size*(i+1)]
if not check.intersection(x):
out.extend(x)
check.update(x)
return out
Tests:
compa = [0, 1, 2, 3, 4, 1, 5, 0, 6, 5, 7, 8, 9, 10, 11, 12, 13, 2]
unique_by_row(compa)
# returns:
[0, 1, 2, 5, 7, 8, 9, 10, 11]
unique_by_row(compa, reverse=True)
# returns:
[12, 13, 2, 9, 10, 11, 5, 7, 8, 3, 4, 1]

Product with descreasing values

I have a 3 lists :
a = [10, 9, 8, 7, 6]
b = [8, 7, 6, 5, 4, 3]
c = [6, 5, 4, 3, 2]
I need to get all the permutations obtained with itertools.product(), BUT only if the values are decreasing:
[10, 8, 6] # is good
[6, 8, 4] # is not good, since 8 > 6
Is there a simple way to do it or should I go with list comprehension and conditions ?
You could do this with a list comprehension by looping over theitertools.product iterator and extracting only those returned items that are sorted in reverse:
[item for item in product(a,b,c) if sorted(item, reverse = True) == list(item)]
Example:
from itertools import product
a = [10,9,8,7,6]
b = [8, 7, 6, 5, 4, 3]
c = [6, 5, 4, 3, 2]
[item for item in product(a,b,c) if sorted(item, reverse = True) == list(item)]
# [(10, 8, 6), (10, 8, 5), (10, 8, 4), (10, 8, 3), (10, 8, 2) ...continues
You can refer following code which does not have list comprehensions:
from itertools import product
a = [10, 9, 8, 7, 6]
b = [8, 7, 6, 5, 4, 3]
c = [6, 5, 4, 3, 2]
for result in product(a,b,c):
if sorted(result, reverse = True) == list(result):
print result
This is a simple one line solution
>>> mylist = [10, 9, 8, 7, 6]
>>> all(earlier >= later for earlier, later in zip(mylist, mylist[1:]))
True
>>> mylist = [10, 9, 7, 8, 6]
>>> all(earlier >= later for earlier, later in zip(mylist, mylist[1:]))
False
I found this here:
Determine if a list is in descending order
If you don't want to use list comprehensions for some reason:
def decreasing(l):
return all(a >= b for a, b in zip(l[:-1], l[1:]))
filter(decreasing, product(a, b, c))

Categories