How to swap elements in tuple? - python

I have a very specific problem where I need to know how to swap elements in a list or tuple.
I have one list that is called board state and I know the elements that need to be swapped. How do I swap them? In java with two-dimensional arrays, I could easily do the standard swap technique but here it says tuple assignment is not possible.
Here is my code:
board_state = [(0, 1, 2), (3, 4, 5), (6, 7, 8)]
new = [1, 1] # [row, column] The '4' element here needs to be swapped with original
original = [2, 1] # [row, column] The '7' element here needs to be swapped with new
Result should be:
board_state = [(0, 1, 2), (3, 7, 5), (6, 4, 8)]
How do I swap?

Tuples, like strings, are immutable: it is not possible to assign to the individual items of a tuple.
Lists are mutable, so convert your board_state to a list of lists:
>>> board_state = [[0, 1, 2], [3, 4, 5], [6, 7, 8]]
And then use the standard Python idiom for swapping two elements in a list:
>>> board_state[1][1], board_state[2][1] = board_state[2][1], board_state[1][1]
>>> board_state
[[0, 1, 2], [3, 7, 5], [6, 4, 8]]

Related

How to split a list into two based on a value?

I am trying to create a function which can separate a list into two new lists based on a value (in this case 3.5).
The code I have tried to make so far makes a list of the first values in the main list (the ones I want to compare). This list is [1,1,3,1,4,4,5,1] I now want to create two lists. This would be [1,1,3,1,1] and [4,4,5]. However, I cannot use > to compare the different values in the list and am unsure how to do so.
As I said above, I'm confused about what your code is trying to do, but you can split a list like this.
my_list=[1,1,3,1,4,4,5,1]
my_val=3.5 #value to split on
list1=[x for x in my_list if x>my_val]
list2=[x for x in my_list if x<my_val]
EDIT
To make this work for a list of tuples, based on their first value, you can do the same but with a slight modification
my_list = [(1, 4, 3, 0),
(1, 7, 6, 0),
(3, 8, 7, 0),
(1, 1, 9, 0),
(4, 1, 1, 0),
(4, 3, 8, 1),
(5, 4, 2, 1),
(1, 7, 7, 1)]
list1=[x for x in my_list if x[0]>my_val]
list2=[x for x in my_list if x[0]<my_val]
The itertools module documentation provides a series of recipes for common tasks. One of them is a partition function.
from itertools import tee, filterfalse
def partition(pred, iterable):
"Use a predicate to partition entries into false entries and true entries"
# partition(is_odd, range(10)) --> 0 2 4 6 8 and 1 3 5 7 9
t1, t2 = tee(iterable)
return filterfalse(pred, t1), filter(pred, t2)
my_list=[1,1,3,1,4,4,5,1]
t1, t2 = partition(lambda x: x > 3.5, my_list)
list1 = list(t1) # [1, 1, 3, 1, 1]
list2 = list(t2) # [4, 4, 5]
You can have a function to split your list for a value.
def split_list(val, _list):
list1 = []
list2 = []
for _x in _list:
(list1 if _x <= val else list2).append(_x)
return list1, list2
# Your example
print(split_list(3.5, [1, 1, 3, 1, 4, 4, 5, 1]))
#brings output
#([1, 1, 3, 1, 1], [4, 4, 5])
And call it repeated for a data set as you said
# For a data set like yours
my_list = [(1, 4, 3, 0),
(1, 7, 6, 0),
(3, 8, 7, 0),
(1, 1, 9, 0),
(4, 1, 1, 0),
(4, 3, 8, 1),
(5, 4, 2, 1),
(1, 7, 7, 1)]
my_list_1 = []
my_list_2 = []
for x in my_list:
g, le = split_list(3.5, x)
my_list_1.append(g)
my_list_2.append(le)
print(my_list_1)
print(my_list_2)
# Separates the list to
[[1, 3, 0], [1, 0], [3, 0], [1, 1, 0], [1, 1, 0], [3, 1], [2, 1], [1, 1]]
[[4], [7, 6], [8, 7], [9], [4], [4, 8], [5, 4], [7, 7]]

Calculating array combinations using recursion

I wish to input an n*m array and the resulting output be an array containing the different combinations of the row elements.
Here's an example to clarify (albeit an extremely simple case):
I wish to input an array of the following shape:
[[1, 2, 3]
[2, 5, 6]]
And wish to receive the following output:
[[1,2], [1,5], [1,6], [2,5], [2,6], [3,2], [3,5], [3,6]]
As you can see [2,2] is not included because of repetition.
I can write quick and dirty code containing nested for loops when the input dimensions are know a priori:
A = [[1, 2, 3], [2, 5, 6]]
m = len(A[0])
for i in range(0, m):
for j in range(0, m):
if A[0][i]!=A[1][j]: #check and eliminate repetition
combined.append([A[0][i],A[1][j])
choice_num.append([i+1, j+1]) #See (**) below
I would really like to know how to implement this as a recursive function so given some input n-D array, A, one can simply call it as:
recursive_looper(A)
(**) Another feature that I would like is for the function to output the column number corresponding to the element used in the combination so we get two outputs:
element values: [[1,2], [1,5], [1,6], [2,5], [2,6], [3,2], [3,5], [3,6]]
element position: [[1,1], [1,2], [1,3], [2,2], [2,3], [3,1], [3,2], [3,3]]
Any tips or suggestions would be greatly appreciated!!
Edit: I am open to any solution that can achieve the desired output. Recursion was simply the first thing that came to mind.
Edit 2 (Extended capabilities): This code must not be restricted to a specific list input shape but be extensible to any array of shape (n,m).
I'll provide an example for where the code breaks down. The work-around was implementing n-1 conditional statements, which I would like to avoid because the array shape must be known a priori.
A = [[2, 4, 1, 11, 3], [3, 2, 1, 4, 11], [2, 3, 4, 17, 13]]
If I do not make any modifications to your indexing/filter I receive the following output for the 'filtered' list:
#[[2, 3, 2], [2, 3, 3], [2, 3, 4], [2, 3, 17], [2, 3, 13], [2, 1, 2], ..., [3, 11, 13]]
Immediately I notice that it only compared element position 0 with position 1 for 'likeness', hence why the first combination contains two 2's.
I can make a modification to the Index grabber and filter loop which looks like so:
for i in range(0, len(projects_master)-2):
indexes = [idx for idx, t in enumerate(prod) if t[i] == t[i+1] or t[i]==t[i+2] or t[i+1] == t[i+2] ]
res = []
for i in range(0, len(A)-2):
res.append(list(filter( lambda v: v[i] != v[i+1] and v[i] != v[i+2] and v[i+1] != v[i+2], prod)))
result = [list(t) for t in res[0]]
This does give the correct output, but like I said, I needed to write out n-1 t[i] and v[i] conditions. How can this be done automatically?
EDIT 3 - FINAL
Thanks a bunch to those who provided different approaches to help me achieve the same end goal. I took some insight from each and wrote something that makes sense to me and seems to function well for any input. The code which filters duplicates and removes them from the combinations is shown below:
ind_remove = []
for i in range(0, len(prod)):
if len(prod[i]) != len(set(prod[i])):
ind_remove.append(i)
adder=0
for i in ind_remove:
del prod[i-adder]
adder=adder+1 #takes into account change in indices after an element is deleted.
You can use itertools.product to generate the required combinations, which works like a cartesion product between two sets to generate the combinations.
So it the lists have been [[1, 2], [3, 4]], the cartesian product within the sublists will be
[[1, 3], [1, 4], [2, 3], [2, 4]]
from itertools import product
a = [[1, 2, 3], [2, 5, 6]]
# Generate all possible products, *a gives you two lists
prod = list(product(*a))
#[(1, 2), (1, 5), (1, 6), (2, 2), (2, 5), (2, 6), (3, 2), (3, 5), (3, 6)]
#Get the list of duplicate indexes
indexes = [idx for idx, t in enumerate(prod) if t[0] == t[1] ]
print(indexes)
#[3]
#Remove tuples who are duplicates
res = list(filter( lambda v: v[0] != v[1], prod))
print(res)
#[(1, 2), (1, 5), (1, 6), (2, 5), (2, 6), (3, 2), (3, 5), (3, 6)]
#Convert the tuples to list
result = [list(t) for t in res]
print(result)
#[[1, 2], [1, 5], [1, 6], [2, 5], [2, 6], [3, 2], [3, 5], [3, 6]]
You can use a function that iterates over the items of the first list of the given list of lists and merge each item with the combinations from the recursive calls:
def nonrepetitive_product(lists):
if not lists:
yield []
return
first, *rest = lists
combinations = list(nonrepetitive_product(rest))
for item in first:
for combination in combinations:
if item not in combination:
yield [item, *combination]
so that given:
l = [[1, 2, 3], [2, 5, 6]]
list(nonrepetitive_product(l)) returns:
[[1, 2], [1, 5], [1, 6], [2, 5], [2, 6], [3, 2], [3, 5], [3, 6]]
If you want the positions and values for any number of rows, you'd be better off using itertools.product and enumerate together. Filtering is a little tricky, but it can be done:
import itertools
A = [[1, 2, 3], [2, 5, 6], [7, 8, 3]]
prod = itertools.product(*map(enumerate, A)) # yields ((i,x),(j,y),(k,z),...) nested tuples
transposed = ([*zip(*pairs)] for pairs in prod) # yields ((i,j,k,...), (x,y,z,...)) 2-tuples
filtered = [(ijk, xyz) for ijk, xyz in transposed if len(xyz) == len(set(xyz))] # filter dupes
indexes, values = zip(*filtered) # you might find `filtered` more useful than separate lists

Python List Comprehension with two cycles

I am a beginner in Python.
I learn list comprehension but my code is bad, because list comprehensions are wrong or missing:
I tried a lot of things, but results are generators or errors. Could you give me advice...?
Thank you.
Acer
import itertools as it
aT=list(it.permutations([4,3,3,0],3))
uT=list(set(aT))
# convert uniqueTimes list of tuples to list of lists
uT=[list(el) for el in uT]
uTt=[el[0]+el[1]+el[2] for el in uT] #It is wrong, I want universal list comprehension :-( when I change members of permutation, e.g.it.permutations([5,4,3,2,1],4))
uTs=[] #It is wrong too, I want universal list comprehension :-(
a=""
for m in range(len(uT)):
for n in range(len(uT[m])):
a+=str(uT[m][n])
uTs.append(a)
a=""
uTcombine=list(it.zip_longest(uTs,uTt)) #result as I expected, but the algorithm is "non comperhesion"
print(uT)
print(uTcombine)
from this (uT - list of lists, where each inner list is unique)
[[0, 3, 3], [3, 4, 3], [0, 3, 4], [3, 0, 3], [3, 4, 0], [3, 0, 4], [4, 0, 3], [4, 3, 3], [3, 3, 4], [3, 3, 0], [0, 4, 3], [4, 3, 0]]
I need that (uTcombine - list of tuples, where first in tuple is [0,3,3] => '033' and second is sum of list's items [0,3,3] => 6
[('033', 6), ('343', 10), ('034', 7), ('303', 6), ('340', 7), ('304', 7), ('403', 7), ('433', 10), ('334', 10), ('330', 6), ('043', 7), ('430', 7)]
You can use existing functions from the standard library instead of writing your own where possible:
uT = [(''.join(map(str, el)), sum(el)) for el in uT]
In this case:
''.join(map(str, el)) converts the permutation to the string representation you wanted (0, 3, 3, ) -> '033' by first coverting each item to string (using map(str, el)), and then joining the strings.
sum(el) summarized the permutation (0, 3, 3, ) -> 6

Using list comprehension, tuples and itertools.groupby

This has been giving me some trouble for a while, maybe I've got tunneled vision. Given a list of integers, generate a new list where every group of adjacent duplicates has been turned into a tuple.
For example, given the list: [1, 2, 3, 3, 4, 5, 5, 5, 6]
The generated list contains: [1, 2, (3, 3), 4, (5, 5, 5), 6]
I'd like to achieve this using list comprehension.
numbers = [1, 2, 3, 3, 4, 5, 5, 5, 6]
it = itertools.groupby(numbers)
numbers = [tuple(group) if len(tuple(group)) > 1 else key for key, group in it]
The result I'm expecting:
[1, 2, (3, 3), 4, (5, 5, 5), 6]
The result I'm getting:
[1, 2, (), 4, (), 6]
The inserted tuples are empty, apparently - but at the same time they're not, since they would have had to have had more than one element in them to get inserted in the first place. What's going on? I'm new to python, and even after exhausting all the keywords I can think of I still haven't been able to find a similar question online. I'm sure it's something simple and I just can't see it. Any help is appreciated.
If you want to do list comprehension
>>>l = [1, 2, 3, 3, 4, 5, 5, 5, 6]
>>>[k[0] if len(k) == 1 else tuple(k) for k in [list(j) for i,j in itertools.groupby(l)]]
[1, 2, (3, 3), 4, (5, 5, 5), 6]
The problem is that the group variable is an iterator that only can be iterated once. It appears empty after exhausting. You need to store the intermediate group temporarily. One way to go is using nested generators/comprehesions as itzmeontv suggested, or to use a mapping function:
def make_group(group):
group = tuple(group)
if len(group) == 1:
return group[0]
return group
numbers = [make_group(group) for key, group in itertools.group_by(numbers)]
You may try this one
a = [1, 2, 3, 3, 4, 5, 5, 5, 6]
[(i,)*a.count(i) if a.count(i)>1 else i for i in set(a)]
output:
[1, 2, (3, 3), 4, (5, 5, 5), 6]

Python Mapping Arrays

I have one array pat=[1,2,3,4,5,6,7] and a second array count=[5,6,7,8,9,10,11]. Is there a way without using dictionaries to get the following array newarray=[[1,5],[2,6],[3,7],[4,8],[5,9],[6,10],[7,11]]?
You can just zip the lists
>>> pat=[1,2,3,4,5,6,7]
>>> count=[5,6,7,8,9,10,11]
>>> list(zip(pat,count))
[(1, 5), (2, 6), (3, 7), (4, 8), (5, 9), (6, 10), (7, 11)]
Or if you want lists instead of tuples
>>> [[i,j] for i,j in zip(pat,count)]
[[1, 5], [2, 6], [3, 7], [4, 8], [5, 9], [6, 10], [7, 11]]
If you want inner elements to be list, you can use -
>>> pat=[1,2,3,4,5,6,7]
>>> count=[5,6,7,8,9,10,11]
>>> newarray = list(map(list,zip(pat,count)))
>>> newarray
[[1, 5], [2, 6], [3, 7], [4, 8], [5, 9], [6, 10], [7, 11]]
This first zips the two lists, combining the ith element of each list, then converts them into lists using map function, and later converts the complete outer map object (that we get from map function) into list
Without using zip, you can do the following:
def map_lists(l1, l2):
merged_list = []
for i in range(len(l1)):
merged_list.append([l1[i], l2[i]])
return merged_list
Or, the equivalent, using a list comprehension instead:
def map_lists(l1, l2):
return [[l1[i], l2[i]] for i in range(len(l1))]

Categories

Resources