Deleting an element from a list in a dictionary - list

This:
deck = {1:[1,2,3,4], 2:[1,2,3,4], 3:[1,2,3,4]}
print(deck)
del deck[1][2]
print(deck)
gives this:
{1: [1, 2, 3, 4], 2: [1, 2, 3, 4], 3: [1, 2, 3, 4]}
{1: [1, 2, 4], 2: [1, 2, 3, 4], 3: [1, 2, 3, 4]}
which is what I expect, but this:
deck = {1:None, 2:None, 3:None}
suit =[1,2,3,4]
for i in range(len(deck)):
deck[i+1] = suit
print(deck)
del deck[1][2]
print(deck)
gives this:
{1: [1, 2, 3, 4], 2: [1, 2, 3, 4], 3: [1, 2, 3, 4]}
{1: [1, 2, 4], 2: [1, 2, 4], 3: [1, 2, 4]}
As you can see the del keyword deletes index 2 for every key value, not just key value 1.
Sorry if this is obvious, I'm learning and confused by this.

Each element in the dict has a reference to the same list. So when you delete an element from one of them, it's visible via all of them (since, as noted, they're actually the same list!).
Instead, each element of the dict should have a different copy of the list:
for i in range(len(deck)):
deck[i+1] = suit[:]
Side note:
This loop could be replaced with a more "pythonic" dict-comprehension:
deck = {i:suit[:] for i in range(1,4)}

Related

Skipping list of lists elements

I have this nested list:
list = [[1, 2, 3, 4],
[2, 7, 2, 1],
[3, 3, 7, 5],
[4, 4, 1, 7]]
And I'm trying to skip the first list of this nested list, and the first element of each list. I want it to become like this:
list = [[7, 2, 1],
[3, 7, 5],
[4, 1, 7]]
So far I have this:
% skip first list in list of lists
skip_first_list([_|Tail], Tail).
% attemping to skip first element in each of the lists
skip_first_list([[_ | HeadTail] | Tail], X) :-
skip_first_list(Tail, R),
append(R, [HeadTail], X).
Which does not produce the correct result:
?- skip_first_list([[1, 2, 3, 4], [2, 7, 2, 1], [3, 3, 7, 5], [4, 4, 1, 7]], X).
X = [[2, 7, 2, 1], [3, 3, 7, 5], [4, 4, 1, 7]] ;
X = [[3, 3, 7, 5], [4, 4, 1, 7], [2, 3, 4]] ;
X = [[4, 4, 1, 7], [7, 2, 1], [2, 3, 4]] ;
X = [[3, 7, 5], [7, 2, 1], [2, 3, 4]] ;
false.
Whereas I'm after this answer:
X = [[7, 2, 1], [3, 7, 5], [4, 1, 7]]
My result so far seems to be showing I'm appending in a reverse/incorrect order, How can I fix this? I don't really understand what order Prolog evaluates expressions. Any any would be appreciated.
Well the specification is that you provide a list of lists and that:
the first sublist is ignored (not part of the output); and
that for the remaining sublists, all heads are ignored as well.
So we better split this into two predicates:
remove_heads/2, which removes the heads of all sublists; and
remove_upper_left/2 which remove the first sublist, and then uses the above predicate to pop the heads of the sublists.
We can perform remove_heads/2 for instance with recursion:
remove_heads([],[]).
remove_heads([[_|H]|T],[H|T2]) :-
remove_heads(T,T2).
finally our remove_upper_left/2 simply ignores the head of the list, and makes a call to remove_heads with the tail:
remove_upper_left([_|T],T2) :-
remove_heads(T,T2).
Or in full:
remove_heads([],[]).
remove_heads([[_|H]|T],[H|T2]) :-
remove_heads(T,T2).
remove_upper_left([_|T],T2) :-
remove_heads(T,T2).
This then produces:
?- remove_upper_left([[1, 2, 3, 4], [2, 7, 2, 1], [3, 3, 7, 5], [4, 4, 1, 7]],X).
X = [[7, 2, 1], [3, 7, 5], [4, 1, 7]].
and works in the opposite direction as well:
?- remove_upper_left(X, [[1, 2, 3, 4], [2, 7, 2, 1], [3, 3, 7, 5], [4, 4, 1, 7]]).
X = [_G1364, [_G1370, 1, 2, 3, 4], [_G1376, 2, 7, 2, 1], [_G1382, 3, 3, 7, 5], [_G1388, 4, 4, 1|...]].
So here it prepends a variable to every list, and prepends a variable (possibly a sublist) to the output.
Furthermore we have here two predicates at the price of one: we can also use remove_heads/2 in the future if we want to pop the heads of all the sublists in a list of lists.

How do I reassign the first index of this matrix 'a' without changing 'b'?

I am trying to change a[0][0] without changing the matrix b. Is there an easy way to do this? I tried to use b = list(a) and b = a[:] but no luck.
a = [[1,2,3,4],[1,2,3,4]]
b = a
print(a)
print(b)
a[0][0] = "WWWW"
print(a)
print(b)
Output:
[[1, 2, 3, 4], [1, 2, 3, 4]]
[[1, 2, 3, 4], [1, 2, 3, 4]]
[['WWWW', 2, 3, 4], [1, 2, 3, 4]]
[['WWWW', 2, 3, 4], [1, 2, 3, 4]]
This worked but it seems like there could be a better way?
a = [[1,2,3,4],[1,2,3,4]]
b = [[0,0,0,0], [0,0,0,0]]
for i in range(len(a)):
for j in range(len(a[i])):
b[i][j] = a[i][j]
print(a)
print(b)
a[0][0] = "WWWW"
print(a)
print(b)
Output:
[[1, 2, 3, 4], [1, 2, 3, 4]]
[[1, 2, 3, 4], [1, 2, 3, 4]]
[['WWWW', 2, 3, 4], [1, 2, 3, 4]]
[[1, 2, 3, 4], [1, 2, 3, 4]]
Lists are mutable.
This link explains in detail what mutable objects are
This doesn't work in your code because, you are using nested lists. If you were to do just a[0]="something", this wouldn't reflect in b however if you do something like this a[0][0]="wow" this would.
b = a[:]
The nested list in both a and b still point towards the same block of memory.
To solve this try:
import copy
a = [[1,2,3,4],[1,2,3,4]]
b = copy.deepcopy(a)
Explained in detail here

Project Euler Number 24

Python 2.7.9
Hello I'm experiencing some problems with how python is handling my permutations algorithm.
So I want my function to take the set_list=[1,2,3,4] and return all the permutations of that list.
This was my idea. Move from left to right, starting at the index values 0,1 of set_list, flip the value of set_list[index] with the value of set_list[index+1], with the understanding that when you reach an end point you flip set_list[0] with set_list[-1]. I thought this was gucci.
Solution
Forward
1234
2134
2314
2341
1342
3142
3412
3421
1423
4123
4213
4231
The idea then being to just to a reverse sort of the previous sub-lists to derive all the possible permutations.
Solution Reverse
4321
4312
4132
1432
2431
2413
2143
1243
3241
3214
3124
1324
My python notes
x = [1,2,3,4]
print(x)
j k k j
x[0],x[1] = x[1],x[0]
print(x)
x[1],x[2] = x[2],x[1]
print(x)
x[2],x[3] = x[3],x[2]
print(x)
x[3],x[0] = x[0],x[3]
print(x)
x[0],x[1] = x[1],x[0]
print(x)
x[1],x[2] = x[2],x[1]
print(x)
x[2],x[3] = x[3],x[2]
print(x)
x[3],x[0] = x[0],x[3]
print(x)
x[0],x[1] = x[1],x[0]
print(x)
x[1],x[2] = x[2],x[1]
print(x)
x[2],x[3] = x[3],x[2]
print(x)
x[3],x[0] = x[0],x[3]
print(x)
Code returns:
[1, 2, 3, 4]
[2, 1, 3, 4]
[2, 3, 1, 4]
[2, 3, 4, 1]
[1, 3, 4, 2]
[3, 1, 4, 2]
[3, 4, 1, 2]
[3, 4, 2, 1]
[1, 4, 2, 3]
[4, 1, 2, 3]
[4, 2, 1, 3]
[4, 2, 3, 1]
[1, 2, 3, 4]
So for a lot of reasons recursively using this function doesn't work (I have no idea why):
def set_return(__LIST__,j,k):
__LIST__[j],__LIST__[k]=__LIST__[k],__LIST__[j]
return(__LIST__)
So I decided to try and sudo-bullshit-hack a solution together, and have only successfully succeed in pulling my hair out.
Step 1)
Create lists containing values from vertical lists of j,k based on characteristics of list x shouldn't be that hard right?
x = [1,2,3,4]
set_0 = range(0,len(x))*(len(x)-1)
set_1 = set_0[1:len(set_0)]+[set_0[0]]
Code Returns:
>>> set_0
[0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3]
>>> set_1
[1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0]
>>>
Step 2)
def shift(__LIST__,a,b):
j = int(__LIST__[a])
k = int(__LIST__[b])
__LIST__[a] = k
__LIST__[b] = j
return(__LIST__)
Code Output:
>>>
[1, 2, 3, 4]
[2, 1, 3, 4]
[2, 3, 1, 4]
[2, 3, 4, 1]
[1, 3, 4, 2]
[3, 1, 4, 2]
[3, 4, 1, 2]
[3, 4, 2, 1]
[1, 4, 2, 3]
[4, 1, 2, 3]
[4, 2, 1, 3]
[4, 2, 3, 1]
[1, 2, 3, 4]
>>> set_0
[0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3]
>>> set_1
[1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0]
>>> shift([1, 2, 3, 4],0,1)
[2, 1, 3, 4]
>>> shift([2, 1, 3, 4],1,2)
[2, 3, 1, 4]
>>> shift([2, 3, 1, 4],2,3)
[2, 3, 4, 1]
>>> shift([2, 3, 4, 1],3,0)
[1, 3, 4, 2]
>>>
So then I use this:
chi = [1,2,3,4]
set_0 = range(0,len(chi))*(len(chi)-1)
set_1 = set_0[1:len(set_0)]+[set_0[0]]
to_return=[]
x = [1,2,3,4]
for i in range(len(set_0)):
insert=shift(x,set_0[i],set_1[i])
to_return.append(insert)
x = insert
And get:
[[1, 2, 3, 4],
[1, 2, 3, 4],
[1, 2, 3, 4],
[1, 2, 3, 4],
[1, 2, 3, 4],
[1, 2, 3, 4],
[1, 2, 3, 4],
[1, 2, 3, 4],
[1, 2, 3, 4],
[1, 2, 3, 4],
[1, 2, 3, 4],
[1, 2, 3, 4]]
Are there easier ways...yes. Can I "protect" x or insert or hell maybe even both with list() ...face palm. Posting anyway. Enjoy.
The issue you are having at the end of your code is that all your insert values are references to the same list x, which gets modified in place by the shift function. You only see [1, 2, 3, 4] values in your to_return list because that's the final value of x. If you printed x while the loop was running you'd see the other permutations, but storing a reference in to_return doesn't preserve the value when x is modified later.
Compare with this:
x = [1, 2]
y = [x, x, x, x] # y contains several references to the list x
print(y) # prints [[1, 2], [1, 2], [1, 2], [1, 2]]
x[0] = 0 # modify x in place
print(y) # prints [[0, 2], [0, 2], [0, 2], [0, 2]], all the 1's are gone!
To fix this issue you can copy the list before appending it to to_return. The copy won't change when you modify x again later. (An alternative solution would be to change shift to return a new list without changing the old one, but I'll leave exploring that option up to you.) When you're storing a copy, you don't even need to care about shift's return value, you can just keep using x directly:
for i in range(len(set_0)):
shift(x,set_0[i],set_1[i]) # ignore the return value, which is another reference to x
to_return.append(x[:]) # append a copy of x
The slice x[:] is a compact way of copying the list. You could use list(x) if you wanted to be a bit more explicit (at the cost of a few extra characters). Either version would be easily understood as a copy by experienced Python programmers.
Before I finish this answer, I want to make a few additional suggestions which are somewhat unrelated to the issue you were asking about.
First off, your algorithm doesn't actually find all the permutations of the list you're giving it. For instance, [4, 3, 2, 1] never appears (nor indeed any permutation where 4 appears directly before 3). So even if the code I suggest above "works" in terms of doing what you want it to do, it may not be doing the right thing in a larger sense.
Second is a matter of style. Python lets you name your variables whatever you like, but it's a very bad idea to use some kinds of names. In several of your functions you're using the name __LIST__ which is a really bad name for an argument. For one thing, double-underscore names are reserved for the interpreter. In some future version, Python might store some special value in the name __LIST__ (overwriting whatever you're using it for). Or it might expect that name to hold some specific kind of value, and break in some way if you store something else in it. So don't use double underscores for arbitrary variables!
Even if we ignore the double underscores, __LIST__ is not a great name because it's really long and hard to type. While a name that's more explicit is often good (e.g. number_of_things may be better than n), you have to balance that with being easy enough to read and type. It's probably not wise to use list, since that's the name of the builtin type, but lst is a pretty common abbreviation of it.
When it comes to names, above all, be consistent. It doesn't really matter if you use a and b for throwaway variables, but it's much more confusing when you sometimes use those, and other times use j, and k (without any obvious distinction between their meanings).
def factorial(n):
c=1
for i in range(1,n+1):
c*=i
return(c)
def set_start(LIST):
to_return=[]
for i in range(len(LIST)):
insert=[]
for x in range(len(LIST)):
if LIST[i]!=LIST[x]:
insert.append(LIST[x])
to_return.append(insert)
return(to_return)
def set_builder(NESTED_LIST):
to_return=[]
for i in range(len(NESTED_LIST)):
to_return.append(set_start(NESTED_LIST[i]))
return(to_return)
def set_chain(NESTED_LIST):
to_return=[]
for i in range(len(NESTED_LIST)):
to_return+=NESTED_LIST[i]
return(to_return)
def set_expand(SET):
to_return=[]
for i in range(len(SET)):
to_return+=[SET[i]]*factorial(len(SET)-1)
return(to_return)
def set_rotation(SET):
set_0 = range(0,len(SET)-1,2)
set_1 = range(1,len(SET),2)
to_return=[]
for i in range(len(set_0)):
to_return+=[SET[set_1[i]],SET[set_0[i]]]
return(to_return)
def recursive_chain(SET):
sub_set_lengths=[]
for i in range(len(SET)):
sub_set_lengths.append(len(SET[i]))
sub_set_lengths = sorted(list(set(sub_set_lengths)),reverse=True)
to_return=[]
for i in range(len(sub_set_lengths)):
insert=[]
for x in range(len(SET)):
if sub_set_lengths[i]==len(SET[x]):
insert+=SET[x]
to_return.append(insert)
return(to_return)
def recursive_return(to_return):
to_return = [to_return]
initialize = set_start(to_return[-1])
while len(to_return[-1])!=2:
to_return+=initialize
to_chain = list(set_builder(list(initialize)))
to_pass = list(set_chain(list(to_chain)))
initialize = list(to_pass)
for i in range(len(to_return)):
if len(to_return[i])!=2:
to_return[i]=set_expand(to_return[i])
to_return = recursive_chain(to_return)
to_return+=[set_rotation(to_return[-1])]
return(to_return)
def PERMUTATIONS(SET):
to_return=[]
to_pop = recursive_return(SET)
while to_pop[-1]!=[]:
insert=[]
for i in range(len(SET)):
insert.append(to_pop[i][0])
to_return.append(insert)
for i in range(len(SET)):
to_pop[i].pop(0)
return(to_return)

How to copy list items certain amount of times?

I have a big list of around 2000 numbers in the list. This is just an example of what I want.
I have list1=[1,2,3,4] and list2=[1,3,2,5]. I want it so that list1[i] will be used list2[i] times in the new list.
So for this example the new list would be:list3=[1,2,2,2,3,3,4,4,4,4,4]
The new list3 has 1x1, 3x2, 2x3, 5x4.
This isn't pretty and isn't particularly easy to understand, but works:
>>> list1 = [1, 2, 3, 4]
>>> list2 = [1, 3, 2, 5]
>>> import itertools
>>> list3 = list(itertools.chain(*[[list1[i]] * count for i, count in enumerate(list2)]))
>>> list3
[1, 2, 2, 2, 3, 3, 4, 4, 4, 4, 4]
Brief explanation...
You can multiply a list:
>>> [1] * 3
[1, 1, 1]
Using this in the list comprehension will get you a list-of-lists:
>>> [[list1[i]] * count for i, count in enumerate(list2)]
[[1], [2, 2, 2], [3, 3], [4, 4, 4, 4, 4]]
You can then use itertools to flatten the list as above.
list1=[1,2,3,4]
list2=[1,3,2,5]
list3 = []
for a, b in zip(list1, list2):
for i in range(b):
list3.append(a)
list3 == [1, 2, 2, 2, 3, 3, 4, 4, 4, 4, 4]
Another alternative:
list1=[1,2,3,4]
list2=[1,3,2,5]
z=[]
for x,y in zip(list1,list2):
z.extend([x] * y)
print z

How to select values 2+ after any number in a list?

Is there any way to select the second, third (etc) value from a value in a list in Groovy? I'm still very new to programming in general and am just wondering if there is an easy way to do this.
For example, if I have the list
[1, 2, 3, 4, 5, 6]
I want to select the next two values after each value using a for loop:
for 1: (1, 2, 3)
for 2: (2, 3, 4)
...and so on.
Is that easily possible? Thanks in advance!
If you're using groovy 1.8.1 or later, you can use the take and drop methods:
def foo = [1, 2, 3, 4, 5, 6]
foo.size().times { i ->
println foo.drop(i).take(3)
}
This will result in
[1, 2, 3]
[2, 3, 4]
[3, 4, 5]
[4, 5, 6]
[5, 6]
[6]
If you want the iteration to stop at the last group of three, try something like this:
def foo = [1, 2, 3, 4, 5, 6]
if (foo.size() > 2) {
(foo.size() - 2).times { i ->
println foo.drop(i).take(3)
}
}
which gives
[1, 2, 3]
[2, 3, 4]
[3, 4, 5]
[4, 5, 6]
If you're not using Groovy 1.8.1+, then you can acheive a similar result by writing a function like so:
List split( List foo, int size ) {
(0..foo.size()-size).collect { foo[ it..it+size-1 ] }
}
Then, you can call this like:
split( [1, 2, 3, 4, 5, 6], 3 )
to print
[[1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6]]