def call(nums):
nums[:] = [x for x in nums if x != 4]
numbers = [4, 5]
print(numbers)
call(numbers)
print(numbers)
The output for the above code is:
[4, 5]
[5]
But if you remove the "[:]", the output becomes the following:
[4, 5]
[4, 5]
I know that [:] makes a copy of the full list, but why the function argument is modified in one case and not in the other?
As you suspected the issue is hiding in the slicer in line:
nums[:] = [x for x in nums if x != 4]
Python is "pass by value" which means that you're not passing the pointer numbers into the function, but a copy of it. So re-assigning a value to a copy of the reference will not change the original reference.
But, when you use the slicer, you're accessing the object behind the reference and changing it directly which is why you see the side effect after you exit the function - when using the "slice".
As Python passes objects by reference, when you execute your function with nums[:] = ... line, you change actual list that you've passed from outside, numbers. When you change line to nums = ..., you just overwrite local variable called nums, without affecting numbers array.
In Python, you can not only slice collections to read them, but you can assign to slices, replacing sliced content.
For example:
>>> a = [0, 1, 2, 3, 4, 5]
>>> a[1:4]
[1, 2, 3]
If you assign to slice, it will replace part of original array:
>>> a[1:4] = ['z']
>>> a
[0, 'z', 4, 5]
But when assigning to slices, array remains the same:
>>> a = [0, 1, 2, 3, 4, 5]
>>> b = a
>>> a[:] = ['z']
>>> a
['z']
>>> b
['z']
As you can see, a and b change at the same time, because when assigning to slice, you don't change object's identity, you only change its contents.
>>> a = [0, 1, 2, 3, 4, 5]
>>> b = a
>>> a = ['z']
>>> a
['z']
>>> b
[0, 1, 2, 3, 4, 5]
This is not the case when you just assign to variable, dropping older array out of scope.
def call(nums):
nums = [x for x in nums if x != 4]
Would only change the value of the name nums function parameter which would accomplish nothing.
def call(nums):
nums[:] = [x for x in nums if x != 4]
Changes the actual value of the list passed in as an argument.
Related
I'm trying to wrap my head around how the return call works in a function. In the example below, I'm assigning 5 to number1 and 6 to number2. Then I return both below. When I print the output, I only get "5" as a result.
Can someone please explain why it's doing this? Why does it not print both numbers?
Thanks!
def numberoutput ():
number1 = 5
number2 = 6
return number1
return number2
print (numberoutput())
Here's a compact way to do the loops that you ask for. Your lists should not contain 1, though.
>>> list1 = list(range(2,11))
>>> list2 = list(range(2,11))
>>> primes = [a for a in list1 if all((a % b) != 0 for b in list2 if a != b) ]
>>> primes
[2, 3, 5, 7]
There are no duplicates in the results, because the comprehension just collects elements of list1. But there are plenty of ways to improve prime number detection, of course. This just shows you how to apply comprehensions to your algorithm.
Try this (change 10 by the number you want)
primes = []
for number in range(1,10):
is_prime = True
for div in range(2, number-1):
if number % div == 0:
is_prime = False
break
if is_prime:
primes.append(number)
Be careful though, this is not efficient at all. A little improvment is to change (number - 1) by int(sqrt(number)). But that's math rules. If you want the first 1000000 primes, that won't work. You wanna perhaps check more advanced methods to find primes if you need more.
Explanation:
you iterate first with all numbers between 1 and 10 - 1 = 9. This number is store into the variable "number". Then you iterate other the possible dividers. If the modulo for each pair of number and divider is 0, then it is not a prime number, you can mark it as not prime (is_prime = False) then quit your loop. At the end of the inner loop, you check the boolean is_prime and then add to the list if the boolean is set at True.
Here's a reasonably efficient way to find primes with a list comprehension, although it's not as efficient as the code by Robert William Hanks that I linked in the comments.
We treat 2 as a special case so we don't need to bother with any higher even numbers. And we only need to check factors less than the square root of the number we're testing.
from math import floor, sqrt
primes = [2] + [i for i in range(3, 100, 2)
if all(i % j != 0 for j in range(3, 1 + floor(sqrt(i)), 2))]
print(primes)
output
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
Here's an alternative (less efficient) version that iterates over your list1 (which isn't really a list, it's a range object).
list1 = range(2, 100)
primes = [i for i in list1 if not [j for j in list1 if j*j <= i and i % j == 0]]
print(primes)
In order to improve an accumulator I am writing a function to test if I am using an accumulator properly but I get stuck when I tried to write it even when I think the rest of my function is well code it.
Any information will be useful if you see something strange
Thanks in advance
def gather_every_nth(L, n):
'''(list, int) -> list
Return a new list containing every n'th element in L, starting at index 0.
Precondition: n >= 1
>>> gather_every_nth([0, 1, 2, 3, 4, 5], 3)
[0, 3]
>>> gather_every_nth(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'], 2)
['a', 'c', 'e', 'g', 'i']
'''
result = []
i = 0
while i < len(L):
result.append(L[i])
i = result + result.append(L[i]) # I am not sure about this...
return result
I don't really understand why you think there is an accumulator here: the only thing that looks like an accumulator is result. But usually the term accumulator is used in the context of recursion.
This line:
i = result + result.append(L[i])
Is clearly problematic: i is supposed to be an index so an int. And here you add None (the result of any .append operation) to a list (?!) and what do you expect the outcome will be?
A way to fix this is simply:
i = i + n
or even shorter:
i += n
Nevertheless, you can reduce your entire code to a one-liner using list comprehension:
def gather_every_nth(L, n):
return [L[i] for i in range(0,len(L),n)]
I need to write a Prolog predicate which calculate the sum of 2 binary numbers represented in list.
The lists are already reversed, for example ([0,1] base 2) = (2 base 10).
It should work with mode binary_plus(+,+,-), for example
?- binary_plus([1,1],[1],X).
X = [0,0,1].
and with mode binary_plus(-,-,+), for example
?- binary_plus(X,X,[0,1]).
X = [1].
Im not allowed using cut sign,findall,negation,or if-then-else.
Here is my code:
is_binary([]).
is_binary([X]):- X is 1.
is_binary([X|Xs]):-
append(_,[1],Xs),
member(X,[0,1]),
is_binary(Xs).
binary_plus([],X,X):-
is_binary(X).
binary_plus(X,[],X):-
is_binary(X).
binary_plus([0|Xs],[Y|Ys],[Y|Zs]):-
binary_plus(Xs,Ys,Zs).
binary_plus([1|Xs],[0|Ys],[1|Zs]):-
binary_plus(Xs,Ys,Zs).
binary_plus([1|Xs],[1|Ys],[0|Zs]):-
binary_plus(Xs,[1],Ws),
binary_plus(Ws,Ys,Zs).
I dont know where i'm wrong because there are some strange issues that i cant solve,
so if someone could help me i would appreciate it.
Thanks.
When describing lists, always consider using DCG notation. For example, in your case, consider writing this as:
:- use_module(library(clpfd)).
binary_addition(Xs, Ys, As) :-
phrase(binary_addition_(Xs, Ys, 0), As).
binary_addition_([], [], 0) --> [].
binary_addition_([], [], 1) --> [1].
binary_addition_([X|Xs], [], C) --> binary_addition_([X|Xs], [C], 0).
binary_addition_([], [Y|Ys], C) --> binary_addition_([C], [Y|Ys], 0).
binary_addition_([X|Xs], [Y|Ys], C0) -->
{ [X,Y] ins 0..1,
Sum #= X + Y + C0 },
sum_carry(Sum, C),
binary_addition_(Xs, Ys, C).
sum_carry(0, 0) --> [0].
sum_carry(1, 0) --> [1].
sum_carry(2, 1) --> [0].
Example queries and their solutions:
?- binary_addition([1,0],[0,1,1], Sum).
Sum = [1, 1, 1] .
?- binary_addition([1,1],[1,0,1], Sum).
Sum = [0, 0, 0, 1] .
?- binary_addition([0,1],[1,1], Sum).
Sum = [1, 0, 1] .
Notice that it also works in the other direction:
?- binary_addition(Xs, Ys, [1,1]).
Xs = [1, 1],
Ys = [] ;
Xs = [],
Ys = [1, 1] ;
Xs = [_G2510, 1],
Ys = [_G2522],
_G2510 in 0..1,
_G2510+_G2522#=1,
_G2522 in 0..1 ;
etc.
You can simply add a reverse/2 goal to binary_addition/3 if you want the reverse list.
Here my take on binary-addition-without-anything. I understand that you are not to use clpfd:
binary_plus(A,B,C) :- binary_plus_0(A,B,C).
binary_plus_0([], [], []).
binary_plus_0([], [B|Bs],[B|Bs]).
binary_plus_0([A|As],[], [A|As]).
binary_plus_0([A|As],[B|Bs],[C|Cs]) :- binary_plus_0(A,B,C,As,Bs,Cs).
binary_plus_0(0,0,0,As,Bs,Cs) :- binary_plus_0(As,Bs,Cs).
binary_plus_0(0,1,1,As,Bs,Cs) :- binary_plus_0(As,Bs,Cs).
binary_plus_0(1,0,1,As,Bs,Cs) :- binary_plus_0(As,Bs,Cs).
binary_plus_0(1,1,0,As,Bs,Cs) :- binary_plus_1(As,Bs,Cs).
binary_plus_1([], [], [1]).
binary_plus_1([], [B|Bs],Cs) :- binary_plus_0([1],[B|Bs],Cs).
binary_plus_1([A|As],[], Cs) :- binary_plus_0([A|As],[1],Cs).
binary_plus_1([A|As],[B|Bs],[C|Cs]) :- binary_plus_1(A,B,C,As,Bs,Cs).
binary_plus_1(0,0,1,As,Bs,Cs) :- binary_plus_0(As,Bs,Cs).
binary_plus_1(0,1,0,As,Bs,Cs) :- binary_plus_1(As,Bs,Cs).
binary_plus_1(1,0,0,As,Bs,Cs) :- binary_plus_1(As,Bs,Cs).
binary_plus_1(1,1,1,As,Bs,Cs) :- binary_plus_1(As,Bs,Cs).
I would like to create multiple boxplot in one graph by using octave. I try to set the x-axis that associates each data.
Here is my code
x = [1, 2, 4];
y1 = [6, 2, 3];
y2 = [1, 7, 3];
y3 = [1, 9, 2];
boxplot ({y1,y2,y3});
set(gca,'XTickLabel',x);
refresh;
but the result looks strange. The axis appears three times.
I want to see x-axis 1 for data y1, 2 for data y2 and 4 for data y3
According to Octave Documentation, I could not find how we could set the axis. I found Matlab could do that :(
Please help me to solve this problem.
Before set(gca,'XTickLabel',x); you have to add set(gca, 'xtick', [1:3]);. This makes sure that each (and only each) box in the plot is assigned an x-axis number before these numbers are overridden by manual labels.
Here's the full code:
x = [1, 2, 4];
y1 = [6, 2, 3];
y2 = [1, 7, 3];
y3 = [1, 9, 2];
boxplot ({y1,y2,y3});
set(gca, 'xtick', [1:3]);
set(gca,'XTickLabel',x);
refresh;
i need a predicate that will produce all the binary number of N digits .
For instance the predicate binary(2,L)
will return L = [[0, 0], [0, 1], [1, 0], [1, 1]].
please do not use findall ....
Once you have a list representing all the numbers with N bits, generating all the numbers of N+1 bits is just a matter of unfolding every N-number [a,b,c,...] into two N+1-numbers: [0,a,b,c,...] and [1,a,b,c,...].
Update:
unfold([], []).
unfold([H|T], [[0|H], [1|H]|L]) :-
unfold(T, L).
bn(N, L) :-
( N = 0
-> L = [[]]
; N1 is N - 1,
bn(N1, L1),
unfold(L1, L)
).
If you need to avoid findall/3, then you need an aggregator to collect the binary numbers:
binary(N, L) :-
collect_binaries(N, [], L).
You then generate one binary at a time and check whether it's already present in the aggregated list:
collect_binaries(N, R, L) :-
length(B, N),
make_binary(B), % make binary of length N
\+ memberchk(B, R),
!,
collect_binaries(N, [B|R], L).
If generating another binary fails, you are done:
collect_binaries(_, L, L).
Generating binaries is simple (I'm using the format you gave in your question: a list of 0/1 values). You iterate over all positions in the list and use either 1 or 0:
make_binary([]).
make_binary([H|T]) :-
member(H, [1,0]),
make_binary(T).
Result:
?- binary(2, L).
L = [[0, 0], [0, 1], [1, 0], [1, 1]]
Yes (0.00s cpu)