Python Object Referencing Workaround - python-3.x

Consider the code below:
outer_list = ['a', 'b', 0]
inner_list = [1, 2, 3]
final = []
for item in inner_list:
outer_list[-1] = item
final.append(outer_list)
print(final)
with output : [['a', 'b', 3], ['a', 'b', 3], ['a', 'b', 3]]
My intended output is: [['a', 'b', 1], ['a', 'b', 2], ['a', 'b', 3]]
I understand this has to do with the fact that Python uses object referencing but i cant seem to find a way around this.
Anyone with a solution or alternative i'd appreciate

Yes you're right. Your assignment at line 6 modifies list outer_list and your append call add references to that list in final. You can work on a copy of outer_list to get your result :
outer_list = ['a', 'b', 0]
inner_list = [1, 2, 3]
final = []
for item in inner_list:
l = outer_list.copy()
l[-1] = item
final.append(l)
print(final)

List concatenation returns a new list object.
outer_list = ['a', 'b']
inner_list = [1, 2, 3]
print([outer_list + [item] for item in inner_list])
You could also achieve using map
print(list(map(lambda item: outer_list + [item], inner_list )))

Related

My code appends the same list 10 times instead of appending 10 randomized lists?

At the moment, the while loop creates one list and appends it 10 times to the results list.
What do I need to change in the def dice() so that the while loop creates 10 different lists and appends them to the results list?
from random import choice
list = [1, 2, 3, 4, "a", "b", "c", "d"]
winner = []
ticket = [1, 2]
results = []
class Die:
def __init__(self, a_list):
self.a_list = a_list
def dice(self):
while len(results) < 10:
results.append(winner)
while len(winner) < 2:
die = choice(self.a_list)
winner.append(die)
print(results)
my_dice = Die(list)
my_dice.dice()
I wrote a different approach using zip, if this works for you:
import random
lis = [1, 2, 3, 4, "a", "b", "c", "d"]
combo_1 = []
ticket = [1, 2]
combo_2 = []
class Die:
def __init__(self, a_list):
self.a_list = a_list
def dice(self):
while len(results) < 10:
combo_2.append(random.choice(self.a_list))
combo_1.append(random.choice(self.a_list))
dice = [list(i) for i in zip(combo_1, combo_2)]
print(dice)
my_dice = Die(lis)
my_dice.dice()
Output:
[['b', 'd'], [3, 'b'], ['c', 'b'], ['d', 2], ['a', 4], ['d', 2], ['c', 'c'], ['b', 'b'], [3, 'b'], [3, 3]]
Currently you never reset winner to be empty, so it just keeps growing in size. But I think you're overcomplicating this.
You don't need a while loop if it's of fixed size - use for loop instead
If the sub-list only has two values, you don't need a loop at all
You're losing some of the benefit of having a class by having global variables
And syntactically list is a bad name for a variable because it shadows the builtin, and I would avoid having a method that prints at the end without returning anything.
How about this?
import random
class Die:
def __init__(self, dice_options):
self.dice_options = dice_options
def dice(self):
return [
[random.choice(self.dice_options), random.choice(self.dice_options)]
for _ in range(10)
]
my_dice = Die([1, 2, 3, 4, "a", "b", "c", "d"])
print(my_dice.dice())
# [[3, 'd'], ['d', 2], ['b', 4], [1, 'd'], [4, 'c'], ['b', 4], [2, 1], ['a', 'd'], ['a', 'd'], ['b', 4]]

How do I order double list of elements of this type: [[1,2,3], [a,b,c]]?

I have a double list of this type: dl = [[13, 22, 41], ['c', 'b', 'a']], in which, each element dl[0][i] belongs a value in dl[1][i] (with the same index). How can I sort my list using dl[0] values as my order criteria, maintainning linked both sublists? Sublist are kind of 'linked data', so the previous dl[0][i] and dl[1][i] values must match their index after sorting the parent entire list, using as sorting criteria, the first sublist values
I expect something like:
input: dl = [ [14,22,7,17], ['K', 'M', 'F','A'] ]
output: dl = [ [7, 14, 17, 22], ['F', 'K', 'A', 'M'] ]
This was way too much fun to write. I don't doubt that this function can be greatly improved, but this is what I've gotten in a very short amount of time and should get you started.
I've included some tests just so you can verify that this does indeed do what you want.
from unittest import TestCase, main
def sort_by_first(data):
sorted_data = []
for seq in data:
zipped_to_first = zip(data[0], seq)
sorted_by_first = sorted(zipped_to_first)
unzipped_data = zip(*sorted_by_first)
sorted_data.append(list(tuple(unzipped_data)[1]))
return sorted_data
class SortByFirstTestCase(TestCase):
def test_sort(self):
output_1 = sort_by_first([[1, 3, 5, 2, 4], ['a', 'b', 'c', 'd', 'e']])
self.assertEqual(output_1, [[1, 2, 3, 4, 5], ['a', 'd', 'b', 'e', 'c']])
output_2 = sort_by_first([[9, 1, 5], [21, 22, 23], ['spam', 'foo', 'bar']])
self.assertEqual(output_2, [[1, 5, 9], [22, 23, 21], ['foo', 'bar', 'spam']])
if __name__ == '__main__':
main()
Updated for what you're looking for, selection sort but added another line to switch for the second list to match the first.
for i in range(len(dl[0])):
min_idx = i
for j in range(i+1, len(dl[0])):
if dl[0][min_idx] > dl[0][j]:
min_idx = j
dl[0][i], dl[0][min_idx] = dl[0][min_idx], dl[0][i]
dl[1][i], dl[1][min_idx] = dl[1][min_idx], dl[1][i]
You can try solving this with a for loop also:
dl = [ [3,2,1], ['c', 'b', 'a'] ]
for i in range(0,len(dl)):
dl[i].sort()
print(dl)

Add two lists onto another list which [duplicate]

This question already has answers here:
How to merge lists into a list of tuples?
(10 answers)
Closed 4 years ago.
So I have two lists right now.
list1 = ['A', 'B', 'C', 'D']
list2 = [1, 2, 3, 4]
How can I merge the lists together to make it look something like this:
list3 = [['A', 1], ['B', 2], ['C', 3], ['D', 4]]
Basically I want to make a list inside a list.
I've been trying for loops but nothing seems to be working for me.
Try this:
list1 = ['A', 'B', 'C', 'D']
list2 = [1, 2, 3, 4]
result = [list(i) for i in zip(list1,list2)]
print(result)
Output:
[['A', 1], ['B', 2], ['C', 3], ['D', 4]]

How to retrieve lists of keys and values of a dictionary through a list comprehension?

This is a MWE that shows what I want to obtain but using a for loop:
a = {'a':1, 'b':2, 'c':3, 'd':4}
b = []
c = []
for key, value in a.items():
b.append(key)
c.append(value)
print(b) # ['a', 'b', 'c', 'd']
print(c) # [1, 2, 3, 4]
I want to obtain the same result in one line using list comprehension.
b,c = [(key, value) for key, value in a.items()] results in an unpack error because it assign to b and c, respectively, the first and second item of a and then it doesn't know where unpack the other items. b,c = [key, value for key, value in a.items()] results again in an error, a syntax one.
b, c = map(list, zip(*a.items()))
print(b)
print(c)
This outputs:
['a', 'b', 'c', 'd']
[1, 2, 3, 4]

How to filter similar edges in a list?

I have a list which contains all the edges of an undirected weighted graph.I further sorted it in increasing order of their edge weights.
The list is as follows
lis = [['B', 'C', 1], ['C', 'B', 1], ['B', 'A', 2], ['C', 'A', 2], ['A', 'C', 2], ['A', 'B', 2], ['D', 'C', 3], ['C', 'D', 3], ['B', 'D', 5], ['D', 'B', 5]]
Now in the list, ['B', 'C', 1], ['C', 'B', 1] means the same thing.That is an edge BC has a weight of 1 and edge CB has a weight of 1.Similarly we have edges AB, BA and so on in the list.
How do I keep only one of the two edges and not both since they both mean the same thing.So for ['B', 'C', 1], ['C', 'B', 1], I only want to keep say ['B', 'C', 1].How do I do that?
I found a similar question but I am not really sure how to implement it in my case.
Removing duplicate edges from graph in Python list
I tried to implement the solution posted in the link for my situtation but doesn't work
def normalize(t):
[n1, n2, dist] = t
if n1 < n2:
return t
else:
return [n2, n1, dist]
unique_edges = set(map(normalize, lis))
Simply sort each item and remove duplicates:
>>> lis = sorted([sorted(item) for item in lis])
>>> [lis[i][::-1] for i in range(len(lis)) if i == 0 or lis[i] != lis[i-1]]
[['C', 'B', 1], ['B', 'A', 2], ['C', 'A', 2], ['D', 'C', 3], ['D', 'B', 5]]

Resources