I am reading "How to Think Like a Computer Scientist: Learning with Python 2nd Edition documentation". At the end of Chapter 9 there is this exercise 11, which asks you to
write Python code to make the doctest pass.
My initial solution:
def add_column(matrix):
"""
>>> m = [[0, 0], [0, 0]]
>>> add_column(m)
[[0, 0, 0], [0, 0, 0]]
>>> n = [[3, 2], [5, 1], [4, 7]]
>>> add_column(n)
[[3, 2, 0], [5, 1, 0], [4, 7, 0]]
>>> n
[[3, 2], [5, 1], [4, 7]]
"""
result = matrix[:]
for index in range(len(matrix)):
result[index] += [0]
return result
if __name__ == "__main__":
import doctest
doctest.testmod()
However this code didn't pass the second test. I changed the body of the for loop to the following:
result[index] = result[index] + [0]
and the code now passes all the tests. But I can't understand how this change in the code solved the problem. I thought result[index] = result[index] + [0] is the explicit form of result[0] += [0], so why the behaviour is different?
Having compared my answer to that code that is provided in the solutions, I suspect the problem might be in how I cloned the list. In the solutions it's done like this: result = [d[:] for d in matrix], in which case my initial for loop would work. But why result = matrix[:] isn't working? Is it creating an alias, not a new object?
Also, can someone explain how [d[:] for d in matrix] is parsed and when such syntax is used? I haven't seen this way of using the for loop before and it hasn't been explained/demonstrated in the lessons.
The list isn't being cloned for the following reason:
result = matrix[:]
does indeed copy the list; but you haven't copied the list items. Python handles list items by reference, so result[0] and matrix[0] will still be pointing to the same list object, even thought result and matrix are different lists.
[d[:] for d in matrix] clones both the main list and the list elements because it iterates over matrix and creates a copy of each element (rather than using the reference to that element) in the new list.
You can also use the copy module, which is especially useful because it handles dicts as well, and with copy.deepcopy you can clone multi-dimensional lists of an unknown depth: http://docspy2zh.readthedocs.org/en/latest/library/copy.html (but fair enough if that is outside the scope of what you're trying to learn here).
As for the difference between '+=' and '= ... + ...', I confess that I am slightly surprised as well. In a situation like this, I would tend towards using result[index].append(0), which would avoid that ambiguity; but that, of course, is not an answer.
Related
I have data in a pandas dataframe that consists of values that increase to a point, and then start decreasing. I am wondering how to simply extract the values up to the point at which they stop increasing.
For example,
d = {'values' : [1, 2, 3, 3, 2, 1]}
df = pd.DataFrame(data=d)
desired result = [1, 2, 3]
This is my attempt, which I thought would check to see if the current list index is larger than the previous, then move on:
result = [i for i in df['values'] if df['values'][i-1] < df['values'][i]]
which returns
[1, 2, 2, 1]
I'm unsure what is happening for that to be the result.
Edit:
Utilizing the .diff() function, suggested by Andrej, combined with list comprehension, I get the same result. (the numpy np.isnan() is used to include the first element of the difference list, which is NaN).
result = [i for i in df['values']
if df['values'].diff().iloc[i]>0
or np.isnan(df['values'].diff().iloc[i])]
result = [1, 2, 2, 1]
You can use .diff() to get difference between the values. If the values are increasing, the difference will be positive. So as next step do a .cumsum() of these values and search for maximum value:
print(df.loc[: df["values"].diff().cumsum().idxmax()])
Prints:
values
0 1
1 2
2 3
I'm wondering if there is a functional way to apply an action to every element of list, in Maxima, without necessarily looping over the list?
e.g. if I would like to remove every element of the list a:[1,2,3] from the list b:[5,4,3,2,1]. Obviously, something like:
f(a,b):=
block(
[aList:a, newList:b],
for k thru length(aList)
do newList: delete(aList[k],newList)
);
I just wondered if there was a more direct way? I thought apply might work, but couldn't figure it out, as it seems to take the whole list as the argument (vs. list elements).
There are a few different ways to accomplish that. One way is to treat the arguments as sets and apply setdifference.
(%i2) a: [1, 2, 3] $
(%i3) b: [5, 4, 3, 2, 1] $
(%i4) setify(a);
(%o4) {1, 2, 3}
(%i5) setify(b);
(%o5) {1, 2, 3, 4, 5}
(%i6) setdifference (setify(b), setify(a));
(%o6) {4, 5}
(%i7) listify(%);
(%o7) [4, 5]
That works if a and b are really sets, i.e. order doesn't matter, and elements are unique.
Another way:
(%i8) sublist (b, lambda ([x], not member(x, a)));
(%o8) [5, 4]
I guess the sublist approach makes fewer assumptions, so it is more generally applicable.
I am trying to write the predicate rowN/3 which returns the n-th element (in this case row) of a matrix.
Example:
?- rowN([[1,2],[3,4],[5,6]], 2, R).
R = [3,4];
No
I am struggling with the counter. I have tried unsuccessfully to find some pretty similar examples. So far I've managed to write this:
Code:
rowN(L,[],[]).
rowN([],X,[]).
rowN([],[],[].
rowN([H|T],X,R) :-
A==X,
A is A + 1,
rowI(T,A,H).
This line does not make much sense:
rowN(L,[],[]).
because the second argument is an integer (if I understand correctly), and you use a list. This is the case with nearly all your arguments. Furthermore you use RowI in your recursive call?
Solution
A solution is to first specify that the first row (I = 1), is equal to the head of the matrix:
rowN([H|_],1,H).
next you need to find an iterative way to enumerate through your matrix. So the header is definitely something of the form:
rowN([H|T],I,X) :-
# ...
Now we will assume that I is not equal to 1 (we will discuss this topic later). In that case we need to traverse the matrix further, so we will take the tail and set the counter I one back. This can be done using:
rowN([_|T],I,X) :-
I1 is I-1,
rowN(T,I1,X).
So our predicate reads:
rowN([H|_],1,H).
rowN([_|T],I,X) :-
I1 is I-1,
rowN(T,I1,X).
Now if you use this predicate, it will give the correct result:
?- rowN([[1,2],[3,4],[5,6]], 2, R).
R = [3, 4] ;
false.
The question is why does the predicate does not generate other results: after showing the first result, for rowN([[1,2],[3,4],[5,6]], 2, R) :- rowN([[3,4],[5,6]],1,[3,4])., it could try to find alternatives. It does so by using the second clause, but then it will eventually run out of rows and call for the rowN([],_,_) predicate, since not of the clauses match, it will fail.
This solution is not perfect: it does not work in all directions correctly, which is in general hard in Prolog. That's why good Prolog programmers have written libraries.
Using swi-prolog's builtin nth1/3
Instead of reinventing the wheel, you can make use of the nth1/3 predicate in swi-prolog. Although the arguments are swapped - you need to call it like nth1(2,[[1,2],[3,4],[5,6]],R). - it has the advantage that it works in more directions that what most people can come up in an fast solution, it is with near certainty bugfree (because it has been tested billions of times by all Prolog programs that use the predicate) and some of these builtins are implemented in C++ making them sometimes faster. For instance:
?- nth1(2, [[1,2],[3,4],[5,6]], R).
R = [3, 4].
?- nth1(I, [[1,2],[3,4],[5,6]], [5,6]).
I = 3.
?- nth1(I, [[1,2],[3,4],[5,6]], R).
I = 1,
R = [1, 2] ;
I = 2,
R = [3, 4] ;
I = 3,
R = [5, 6].
?- nth1(I,M,[2,3]).
I = 1,
M = [[2, 3]|_G23] ;
I = 2,
M = [_G22, [2, 3]|_G26] ;
I = 3,
M = [_G22, _G25, [2, 3]|_G29] ;
I = 4,
M = [_G22, _G25, _G28, [2, 3]|_G32] .
You can thus ask what the second row is, ask where the row [5,6] is located, make the query more generic by answering with tuples of the index I and the row R and generate a matrix with a row [2,3] somewhere.
intention is to infinitely cycle through a list, then just do this:
l=[1,2,3,4,5]
after first loop
l=[5,1,2,3,4]
after second loop
l=[4,5,1,2,3]
and so on,
without using double ended queue, itertool
use only simple list
You can do it simply using this:
l = l[-1:] + l[0:-1]
So after
first iteration it will be [5, 1, 2, 3, 4],
after second [4, 5, 1, 2, 3]
If you actually want to modify the list inplace, you have to change its elements explicitly. This is done like this:
def inplace_rotate(l):
l[:] = l[-1:] + l[0:-1]
This way, you do not reassign to the name l, but to the elements of the name l, which is visible to any code holding a reference to the initial l object.
You can also rotate multiple steps at the same time:
def inplace_rotate(l, count=1):
if l and count:
count %= len(l)
l[:] = l[-count:] + l[0:-count]
Not a homework question.
I was going through the questions here and I came across this question.
Someone has answered it. I have tried a lot to understand the recursion used but I am not able to get it. Could someone explain it to me?
Write a function, for a given number, print out all different ways to make this number, by using addition and any number equal to or smaller than this number and greater than zero.
For example, given a = 5, we have the following seven ways to make up 5:
1, 1, 1, 1, 1
1, 4
1, 1, 1, 2
1, 1, 3
2, 3
1, 2, 2
5
The solution from the site is in C++:
void printSeq( int num , int a[] , int len , int s )
{
if( num <= 0 )
{
for( int j = 0 ; j < len ; j++ )
cout << a[ j ] << "," ;
cout << endl;
return;
}
for(int i = s ; i <= num ; i++)
{
a[ len ] = i;
printSeq( num - i , a , len + 1 , i );
}
}
int main()
{
int a[5];
printSeq(5,a,0,1);
cin.get();
return 0;
}
When facing a problem like this it is often a good idea to take a step back from your editor/IDE and think about the problem by drawing out a simple case on a whiteboard. Don't even do pseudo-code yet, just draw out a flowchart of how a simple case (e.g. a = 3) for this problem would turtle all the way down. Also, don't worry about duplicate combinations at first. Try to find a solution which gives you all the desired combinations, then improve your solution to not give you duplicates. In this case, why not look at the manageable case of a = 3? Let me draw a little picture for you. A green checkmark means that we have arrived at a valid combination, a red cross means that a combination is invalid.
As you can see, we start with three empty subcombinations and then build three new subcombinations by appending a number to each of them. We want to examine all possible paths, so we choose 1, 2 and 3 and end up with [1], [2] and [3]. If the sum of the numbers in a combination equals 3, we have found a valid combination, so we can stop to examine this path. If the sum of the numbers in a combination exceeds 3, the combination is invalid and we can stop as well. If neither is the case, we simply continue to build combinations until we arrive at either a valid or invalid solution.
Since your question seems to be primarily about how to work out a recursive solution for this kind of problems and less about specific syntax and you just happened to find a C++ solution I am going to provide a solution in Python (it almost looks like pseudo code and it's what it know).
def getcombs(a, combo = None):
# initialize combo on first call of the function
if combo == None:
combo = []
combosum = sum(combo) # sum of numbers in the combo, note that sum([]) == 0
# simple case: we have a valid combination of numbers, i.e. combosum == a
if combosum == a:
yield combo # this simply gives us that combination, no recursion here!
# recursive case: the combination of numbers does not sum to a (yet)
else:
for number in range(1, a + 1): # try each number from 1 to a
if combosum + number <= a: # only proceed if we don't exceed a
extcombo = combo + [number] # append the number to the combo
# give me all valid combinations c that can be built from extcombo
for c in getcombs(a, extcombo):
yield c
Let's test the code!
>>> combos = getcombs(3)
>>> for combo in combos: print(combo)
...
[1, 1, 1]
[1, 2]
[2, 1]
[3]
This seems to work fine, another test for a = 5:
>>> combos = getcombs(5)
>>> for combo in combos: print(combo)
...
[1, 1, 1, 1, 1]
[1, 1, 1, 2]
[1, 1, 2, 1]
[1, 1, 3]
[1, 2, 1, 1]
[1, 2, 2]
[1, 3, 1]
[1, 4]
[2, 1, 1, 1]
[2, 1, 2]
[2, 2, 1]
[2, 3]
[3, 1, 1]
[3, 2]
[4, 1]
[5]
The solution includes all seven combinations we were looking for, but the code still produces duplicates. As you may have noticed, it is not necessary to take a number smaller than the previous chosen number to generate all combinations. So let's add some code that only starts to build an extcombo for numbers which are not smaller than the currently last number in a combination. If the combination is empty, we just set the previous number to 1.
def getcombs(a, combo = None):
# initialize combo on first call of the function
if combo == None:
combo = []
combosum = sum(combo) # sum of numbers in combo, note that sum([]) == 0
# simple case: we have a valid combination of numbers, i.e. combosum == a
if combosum == a:
yield combo # this simply gives us that combination, no recursion here!
# recursive case: the combination of numbers does not sum to a (yet)
else:
lastnumber = combo[-1] if combo else 1 # last number appended
for number in range(lastnumber, a + 1): # try each number between lastnumber and a
if combosum + number <= a:
extcombo = combo + [number] # append the number to the combo
# give me all valid combinations that can be built from extcombo
for c in getcombs(a, extcombo):
yield c
Once again, let's test the code!
>>> combo = getcombs(5)
>>> for combo in combos: print(combo)
...
[1, 1, 1, 1, 1]
[1, 1, 1, 2]
[1, 1, 3]
[1, 2, 2]
[1, 4]
[2, 3]
[5]
The presented solution may not be the most efficient one that exists, but hopefully it will encourage you to think recursively. Break a problem down step by step, draw out a simple case for small inputs and solve one problem at a time.
Leaving the solution aside for moment and looking at the problem itself:
Compare this problem to insertion sort for an array(or any recursive algorithm). In insertion sort at any point during the execution we have a part of the array that is sorted and another part that is unsorted. We pick an element from the unsorted part and find it's place in the sorted part, thereby extending the sorted part, making the problem smaller.
In case of this problem, we have a fixed number of elements we can choose from i.e integers 1 to the number in the problem(let's call it N), to be a part of the sequence that sums up to N.
At any point we have collected some numbers that sum up to less than N(say X), reducing the problem to N-X size, also reducing our choices from 1..N to 1..(N-X) for the next recursion.
The solution does the obvious, making each choice from 1 to (N-X) and proceeding recursively till X=N. Every time the algorithm reaches X=N, means a permutation is found.
Note: One problem I see with the solution is that it needs to know the number of permutations that will be found beforehand.
int a[5];
This could cause problems if that value is unknown.