I don't understand that part of code about recursive (python) - python

I don't understand recursive part.
def length(list1):
if list1 == [] or list1 == "":
return 0
else:
return 1+length(list1[1:])
a = [1,2,3,4,5]
print "Length of list is: ",length(a)
This is code. and that code's role is like len function.
and output is for a; 5
but return 1+length(list1[1:]) that part is not understandable for me.
why there is "1"? and why it starts with 1? why not "0"?
I thought length(list1[0:]) but it doesn't run.
actually i think but, ı understand nothing about that part.
can anyone explain?

The length of a list can be defined recursively as:
0 if the list is empty (equal to the empty list [])
1 + the length of the list deprived of its first element. (e.g. if you have a list with 3 elements, the length is the same as 1 + the length of the same list without one of its element (2))
Here, list1[1:] is a new list similar to list1 but without the first element.
If we take a concrete example with the list ['a', 'b', 'c']:
['a', 'b', 'c'] is different than the empty list [], then we return 1 + length(['b', 'c']). ['b', 'c'] is different than the empty list [], then length(['b', 'c']) returns 1 + length(['c']); and so on until length([]) is called.

In python: a[1:] means "take all values of a starting from 1, so excluding 0", for instance:
"abc"[1:] == "bc"
[2, 3, 4][1:] == [3, 4]
The function you are looking at takes either a list or a string, then remove an item and counts the remaining until it find an empty one, in this case returns its length (0).

Related

Reorder the position of the string in the list based on similarity

I have a list of string like this -
list = ["A","V","C,"D",X","Y","V_RT","D_RT"]
I want to reorder the strings with suffix "_RT" right after the parent string(string without the suffix).
For example, the above string should become something like this -
list = ["A","V","V_RT","C,"D","D_RT",X","Y"] #notice how the strings with _RT moved after the string without _RT.
My approach-
Right now I am finding the strings with _RT, then searching the index of the parent string without _RT and then inserting it there. Finally, deleting the original prefixed string.
The above approach works but I believe there must be some short(one-two liner way) of doing the required which I don't know.
Please help.
Thanks.
EDIT
I forgot to mention but can't change the order of appearance. After "A", there will be "V" then "V_RT", "C", "D", "D_RT", etc. The strings are not necessarily of length 1. The above is just an example.
Another approach using for-loop
Check if current element + '_RT' is in original list
if True add current element and current element + '_RT' to the new list
if False and also if substring '_RT' is not in current element add the element to the new list
Code:
l = ["A","V","C","D","X","Y","V_RT","D_RT"]
l2 = []
for x in l:
if x+'_RT' in l:
l2+=[x, x+'_RT']
elif '_RT' not in x:
l2.append(x)
print(l2)
Output:
['A', 'V', 'V_RT', 'C', 'D', 'D_RT', 'X', 'Y']
This does it
list1 = ["A","V","C" ,"D","X","Y","V_RT","D_RT"]
dict1={}
for x in list1:
dict1[x[0]]=x
list2=[]
for key,value in dict1.items():
list2.append(key)
if key!=value:
list2.append(value)
print(list2)

How to return the remaining elements of a list after the last match?

Below is my input
x = ['P' 'AE2' 'A' 'AE1' 'B' 'C']
My function is to return the last value within x that contains 0, 1, or 2 at the end of the value
i.e. 'AE2' or 'AE1'
and then any remaining values
Desired Output
y = ['AE1' 'B' 'C']
The values of x can vary thus the values of y will vary as well. I'm struggling on how to create a function for this problem.
Use this:
reversed()
It should work.
You can access the index this way:
for i, e in reversed(list(enumerate(a))):
print i, e
prints
2 baz
1 bar
0 foo
You do not need a loop, Thats the fun of python.
You can access list items easily
li[:] - This access the item 0 - nth.
li[x:] - Accesses x place till end. (x position could be 2,3 or any)
li[::-1] - Reverses the list.
You can assign the manipulated list to a new list.
new_list = li[0:3] (It will store list item 0 - 3 index in the new_list)
Dig more about list manipulation in python, you would know more.
Simply move backwards:
x= ['P', 'AE2', 'A', 'AE1', 'B', 'C']
for index in range(len(x)-1,-1,-1):
if x[index][-1] in "012":
print(x[index:])
break
['AE1', 'B', 'C']
You can use itertools.accumulate to do this in O(n)
from itertools import accumulate
x = ['P', 'AE2', 'A', 'AE1', 'B', 'C']
list(accumulate(x, lambda p,n: [n] if n[-1] in '012' else list(p)+[n]))[-1]
['AE1', 'B', 'C']
If you're a beginner, it might be good to try keep it as simple as possible. Divide the problem into three sections:
Find the index of the last element that match our condition.
Confirm that such an element actually exist!
Print the elements.
First section suggests that you have to loop through the list and check against all elements. Since you also need the index, as well as the element, it seems like you need to use a for loop with enumerate. What this do is to return the index of the element and the element itself. This is common to do in Python.
Next you need to check if the element ends with what you want. Luckily, Python's strings has a method called endswith that returns True if a string ends with any of the values passed to it.
Lastly, you just need to print from the index you've found and onward! Here's a more concrete example:
x = ['P', 'AE2', 'A', 'AE1', 'B', 'C']
matches = ('0', '1', '2')
# Gets the index of the last element that ends with 0, 1 or 2. We start off by going through each element one by one,
# and if the element match our condition, we save the element's index (the variable i). If we later find another element
# in the list we just override the current index.
index = -1
for i, element in enumerate(x):
if element.endswith(matches):
index = i
# If index still is -1, that means no elements matched our condition.
if index == -1:
print('We did not find any element that ended in 0, 1 or 2!')
else:
# Print all contents of x from index to the end.
print(x[index:])

How to force Python to correctly identify list element index in FOR loop

There is a simple list, for example,
my_list = ['a', 'b', 'b', 'c', 'c']
I want to run through my_list[1:] with for loop to get previous element value for each iteration:
for i in my_list[1:]:
print(my_list[my_list.index(i)-1])
I expected to see a b b c on output, but get a a b b instead.
I guess this is because index() method search only for first i value, ignoring the fact that there are two elements "b" as well as two "c"...
How to fix this code to get expected output?
The list.index() method will return the index of first occurrence of its argument. And since you have multiple duplicate items in your list it doesn't give you the expected result. You can use a simple slicing to get your expected output:
>>> my_list = ['a', 'b', 'b', 'c', 'c']
>>>
>>> my_list[:-1]
['a', 'b', 'b', 'c']
Or if you want to access these items through a loop you can use zip() function like following:
>>> for i, j in zip(my_list,my_list[1:]):
... print(i, j)
...
a b
b b
b c
c c
Matching elements with their predecessors or sucessors is a common use case for zip:
In [13]: for i,prior in zip(my_list[1:], my_list[0:]):
print (prior)
....:
a
b
b
c
You can always emulate the behaviour of C/Pascal/Perl/whatever 'for' instead of Python 'for' (which is actually more like foreach). Note that the range starts with 1 to avoid returning the last element on the first iteration.
for i in range(1, len(my_list)):
print(my_list[i], my_list[i-1])
Not very Pythonic, but this approach is sometimes more intuitive for people with background in other languages.
As you noticed, using index does not work here, as it always finds the first position of the given element. Also, it is pretty wasteful, as in the worst case you have to search the entire list each time.
You could use enumerate with start parameter to get the element along with its index:
start = 1
for i, x in enumerate(my_list[start:], start):
print(i, x, my_list[i-1]) # index, current, last
This will do the trick:
for i in range(len(my_list)+1):
try: print(my_list[i-1])
except: print 'it is 1st iteration'

How do I append items from a list to another stopping at a specific value?

I'm building a game of Othello, so I have a list of coordinates that are either b or w on the board.
For example I have lists of coordinates within a list as such
list_a = [ [[1,2],[1,3],[1,4],[1,5],[1,6]], [[2,3],[3,4],[4,5]], [[3,5],[2,5],[1,5]] ]
list 1 is [[1,2],[1,3],[1,4],[1,5],[1,6]] ### [1,4] is 'b' everything else is 'w'
list 2 is [[2,3],[3,4],[4,5]] ### everything is 'w', no 'b'
third list is [[3,5],[2,5],[1,5]] ### [1,5] is 'b'
list_b = []
I want to add all the coordinates that are w into list_b stopping at b, but I don't want to append any w if it doesn't have a b after it.
Ideally, I want my list_b to be
[ [[1,2],[1,3]], [[3,5],[2,5]] ]
I don't mind if it's
[ [[1,2],[1,3],[1,4]], [[3,5],[2,5],[1,5] ]
I can just remove the b coordinates later.
What's the best way to do this? I'm currently building this within a class and using for loops, while True, if statements etc.
You never stated what the board was or how the coordinates are connected to it (perhaps something like [1, 4] for board[1][4] == 'b'?), so I'll just use the string values you're referring to, e.g. 'wwbww' instead of [[1,2],[1,3],[1,4],[1,5],[1,6]].
import itertools
list_a = ['wwbww', 'www', 'wwb']
result = [list(itertools.takewhile(lambda x: x!='b', item)) for item in list_a if 'b' in item]
Result:
>>> result
[['w', 'w'], ['w', 'w']]
result is a list comprehension where each item first checks if it contains a 'b' (since you only want the 'w's if there's a 'b' in there somewhere), and then creates a list out of an itertools.takewhile() call. This function grabs every element from an iterable until the given function returns a falsey value. To expand:
import itertools
def okay_to_add(x):
return x != 'b'
result = []
for item in list_a:
if 'b' in item:
temp = []
for c in itertools.takewhile(okay_to_add, item):
temp.append(c)
result.append(temp)
The result is identical.
You'll have to create an okay_to_add function of your own that, instead of a simple x != 'b', looks up the given coordinate in the board and returns whether it's the 'b' (or 'w', for the other player) that you're interested in.

having trouble with lists in python

The function satisfiesF() takes a list L of strings as a paramenter. function f takes a string as a parameter returns true or false. Function satisfiesF() modifies L to contain only those strings,s for which f(s) returns true.
I have two different programs aimed to produce the same output. But I am getting different outputs.
First program:
def f(s):
return 'a' in s
def satisfiesF(L):
k=[]
for i in L:
if f(i)==True:
k.append(i)
L=k
print L
print
return len(L)
L = ['a', 'b', 'a']
print satisfiesF(L)
print L
Output:
['a', 'a']
2
['a', 'b', 'a']
Second program:
def f(s):
return 'a' in s
def satisfiesF(L):
for i in L:
if f(i)==False:
L.remove(i)
print L
print
return len(L)
L = ['a', 'b', 'a']
print satisfiesF(L)
print L
output:
['a', 'a']
2
['a', 'a']
Please explain why these are giving differnt outputs.
In your second function you are seeing 2 as the length and all the elements in L outside the function because you are setting a local variableL which is a reference to k, your L created outside the function is not affected. To see the change in L you would need to use L[:] = k, then printing L will give you ['a', 'a'] outside the function as you are changing the original list object L list passed in to the function.
In the first you are directly modifying L so you see the changes in L outside the function.
Also never iterate over a list you are removing element from, if you make
L = ['a', 'b', 'a','a','d','e','a'], you will get behaviour you won't expect. Either make a copy for i in L[:] or use reversed for i in reversed(L):
In the first function, you assign over L in satisfiesF(), but you never modify the original list. When you write L=k, that makes the reference L now refer to the same list as k. It doesn't assign to the original list.
In contrast, in the second function you modify L without reassigning to it.
Also, as a side note, you shouldn't modify a list while you iterate over it.
As a second side note, you can rewrite satisfiesF as a one-liner:
L = [item for item in L if f(item)]
This was down voted mistakenly. The question was changed. So, the answer got outdated. Following is the answer for changed question:
L=k
Above would mean that we lost the reference to L.
So, Try this:
To the 1st program, comment the above assignment, do below, to retain reference to L:
# L=k
del L[:]
L[:] = k
Now both programs will output same, below one:
['a', 'a']
2
['a', 'a']
Best of luck.
In the question, there are two Ls. A global one and a local one. The
print L
statement prints the GLOBAL L, which you did not mutate in the programme.
Therefore, in order to let the programme knows that you want to mutate the global L, instead of the local L, you can add the line
globals()['L'] = L
to your first programme. I hope this can help!
In the first program, if you want to mutate the original list L and see the change made by your function, you should replace L = K in your code with L[:] = k:
def satisfiesF(L):
k=[]
for i in L:
if f(i)==True:
k.append(i)
# new code --------
L[:] = k # before: L = K
# -----------------
print L
print
return len(L)
This will give you ['a', 'a'] outside the function.
About mutating a list within a loop in the second program...
Just to remember that during a "for" loop, python keeps track of where it is in the list using an internal counter that is incremented at the end of each iteration.
When the value of the counter reaches the current length of the list, the loop terminates. This means that if you are mutating the list within the loop you can have surprising consequence.
For example, look at the for loop below:
my_list = ['a', 'b', 'c', 'd']
>>>print "my_list - before loop: ", my_list
my_list - before loop: ['a', 'b', 'c', 'd']
for char in my_list:
if char == 'a' or char == 'b':
my_list.remove(char)
>>>print "my_list - after loop: ", my_list
my_list - after loop: ['b', 'c', 'd']
Here, the hidden counter starts out at the index 0, discovers that "a" (in my_list[0]) is in the list, and remove it, reducing the length of my_list to 3 (from the initial 4). The counter is then incremented to 1, and the code proceeds to check the "if" condition, at the position my_list[1], in the mutated list (now of len == 3). This means that you will skip the "b" character (present now at the index 0) even if it had to be remove it.
One solution for this is to use slicing to clone and create a new list where you can remove items from it:
cloneList = my_list[:]

Categories

Resources