Related
For example lets say I have a list as below,
list = ['list4','this1','my3','is2'] or [1,6,'one','six']
So now I want to change the index of each element to match the number or make sense as I see fit (needn't be number) like so, (basically change the index of the element to wherever I want)
list = ['this1','is2','my3','list4'] or ['one',1,'six',6]
how do I do this whether there be numbers or not ?
Please help, Thanks in advance.
If you don't wanna use regex and learn it's mini language use this simpler method:
list1 = ['list4','this1', 'he5re', 'my3','is2']
def mySort(string):
if any(char.isdigit() for char in string): #Check if theres a number in the string
return [float(char) for char in string if char.isdigit()][0] #Return list of numbers, and return the first one (we are expecting only one number in the string)
list1.sort(key = mySort)
print(list1)
Inspired by this answer: https://stackoverflow.com/a/4289557/11101156
For the first one, it is easy:
>>> lst = ['list4','this1','my3','is2']
>>> lst = sorted(lst, key=lambda x:int(x[-1]))
>>> lst
['this1', 'is2', 'my3', 'list4']
But this assumes each item is string, and the last character of each item is numeric. Also it works as long as the numeric parts in each item is single digit. Otherwise it breaks. For the second one, you need to define "how you see it fit", in order to sort it in a logic.
If there are multiple numeric characters:
>>> import re
>>> lst = ['lis22t4','th2is21','my3','is2']
>>> sorted(lst, key=lambda x:int(re.search(r'\d+$', x).group(0)))
['is2', 'my3', 'list4', 'this21']
# or,
>>> ['is2', 'my3', 'lis22t4', 'th2is21']
But you can always do:
>>> lst = [1,6,'one','six']
>>> lst = [lst[2], lst[0], lst[3], lst[1]]
>>> lst
['one', 1, 'six', 6]
Also, don't use python built-ins as variable names. list is a bad variable name.
If you just want to move element in position 'y' to position 'x' of a list, you can try this one-liner, using pop and insert:
lst.insert(x, lst.pop(y))
If you know the order how you want to change indexes you can write simple code:
old_list= ['list4','this1','my3','is2']
order = [1, 3, 2, 0]
new_list = [old_list[idx] for idx in order]
If you can write your logic as a function, you can use sorted() and pass your function name as a key:
old_list= ['list4','this1','my3','is2']
def extract_number(string):
digits = ''.join([c for c in string if c.isdigit()])
return int(digits)
new_list = sorted(old_list, key = extract_number)
This case list is sorted by number, which is constructed by combining digits found in a string.
a = [1,2,3,4]
def rep(s, l, ab):
id = l.index(s)
q = s
del(l[id])
l.insert(ab, q)
return l
l = rep(a[0], a, 2)
print(l)
Hope you like this
Its much simpler
I have defined a recursive function delete() that takes in two parameters:
lst : of type list
to_delete : a value that needs to be removed from the list
However, I have used the function del(), one that we haven't learned yet. So I am wondering whether there is a simpler way to output the same solution without the use of the function del()
This is my code:
def delete(lst, to_delete):
"""
parameters : lst of type list
to_delete : represents a value one wants to delete from the list
returns : another list with the same elements minus the ones one asks to delete
"""
if not lst:
return []
else:
if lst[0] == to_delete:
del lst[0]
return delete(lst[1:], to_delete)
return [lst[0]] + delete(lst[1:], to_delete)
print(delete([1,2,3,4,5,5,6,5,7,5], 5))
Output:
> [1,2,3,4,6] #where is 7 ?
7 is missing, because you return delete(lst[1:], to_delete) even when you just deleted lst[0]: You should use delete(lst[0:], to_delete) here.
The alternative is not to del the 0th element and just return delete(lst[1:], to_delete).
Instead of doing this recursively, you can also just use a list comprehension:
.
def delete(lst, to_delete):
return [element for element in lst if element != to_delete]
Using Recursion
Even with recursion, you don't need to use del:
def delete(lst, to_delete):
"""
parameters : lst of type list
to_delete : represents a value one wants to delete from the list
returns : another list with the same elements minus the ones one asks to delete
"""
if not lst:
return []
if lst[0] == to_delete:
return delete(lst[1:], to_delete)
return [lst[0]] + delete(lst[1:], to_delete)
As you can see, you are repeating yourself a bit (delete(lst[1:], to_delete) is used twice), so you can shorten this to:
def delete(lst, to_delete):
"""
parameters : lst of type list
to_delete : represents a value one wants to delete from the list
returns : another list with the same elements minus the ones one asks to delete
"""
if not lst:
return []
start = [] if lst[0] == to_delete else [lst[0]]
return start + delete(lst[1:], to_delete)
I don't know about its performance though.
No Recursion
If you don't need to use recursion, you can use list comprehensions for much less code:
def delete(lst, to_delete):
return [x for x in lst if x != to_delete]
In case you don't know list comprehensions well, this is logically equivalent to the following:
def delete(lst, to_delete):
res = []
for x in lst:
if x != to_delete:
res.append(x)
return res
EDIT: I missed it, but the reason you don't see 7 in the output is, that del lst[0] already removes the first value from the list and so, you are missing the "new" first value of the list.
You seem to be interested in recursion. Recursion is a functional heritage and so I will give you a glimpse of a functional perspective on the problem. Below, delete is a specialization of filter, which is a specialization of reduce, a simple recursive form -
def reduce (f, state = None, xs = [], i = 0):
if i >= len (xs):
return state
else:
return reduce \
( f
, f (state, xs[i], i)
, xs
, i + 1
)
def filter (f, xs = []):
return reduce \
( lambda acc, x, i:
acc + [x] if f (x) else acc
, []
, xs
)
def delete (q, xs = []):
return filter \
( lambda x: q != x
, xs
)
print (delete (5, [ 1, 2, 5, 3, 5, 5, 2, 3, 1, 5, 1 ]))
# [1, 2, 3, 2, 3, 1, 1]
print (delete ('x', 'abxcdxefxghxi'))
# ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']
Functional style is not the idiomatic style of Python. Those wishing to explore functional style in Python are not completely ignored however. You can find reduce and filter (among many other useful functions) tucked away in Python's functools module.
The definitions of reduce and filter here are my own. If you use functools, you'll want to read up on specific behaviors more closely.
It would be much simpler to recreate your list without the unwanted items:
def delete(lst, to_delete):
return [x for x in lst if x!=to_delete]
print(delete([1,2,3,4,5,5,6,5,7,5], 5))
# [1,2,3,4,6,7]
Correcting your code (but leaving recursion out of it) would look like this:
def delete(lst, to_delete):
"""
parameters : lst of type list
to_delete : represents a value one wants to delete from the list
returns : another list with the same elements minus the ones one asks to delete
"""
if not lst:
return []
else:
res = []
for item in lst:
if item == to_delete:
continue
else:
res.append(item)
return res
which has the same result.
Finally, the recursive option which I highly discourage for this application is the following:
def delete(lst, to_delete, res=[]):
"""
parameters : lst of type list
to_delete : represents a value one wants to delete from the list
returns : another list with the same elements minus the ones one asks to delete
"""
if not lst:
return res
else:
item = lst[0]
if item != to_delete:
res.append(item)
return delete(lst[1:], to_delete, res=res)
If I have something like:
list = [[1,2,3],[4,5,6],[7,8,9]]
Then how do I check if 1 is in the first, second, or third array?
I want it to be able to make an expression such as:
if 1 is in list 1:
do something
elif i is in list 2:
do something
else:
do something
Try using any:
any(1 in sub for sub in [[1,2,3],[4,5,6],[7,8,9]])
>>> list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> any(1 in sub for sub in list)
True
>>> any(10 in sub for sub in list)
False
>>> any(7 in sub for sub in list)
True
>>>
Well, if you know the contents of the list, you can use
if 1 in list[0]:
do_something()
elif 1 in list[1]:
do_something_else()
else: # 1 is in list[2]
do_something_different()
Derived from "Dive Into Python"
list = [[1,2,3],[4,5,6],[7,8,9]]
if 1 in list[0]:
do something
elif 1 in list[1]:
do something
else:
do something
...and so on. The in keyword takes a preceding value argument and returns a true if that value is in the proceeding list, false otherwise. The only other thing to know is list[0] accesses your first element in the top level list (the first sublist) and so on, allowing it to be searched for a specific integer using the in keyword.
Here's the expected output:
>>> list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> 1 in list[0]
True
>>> 1 in list[1]
False
To search all lists you can use the for keyword to loop over your lists and any to return true if any of the sublists match.
>>> any(1 in sublist for sublist in list)
True
>>> any(42 in sublist for sublist in list)
False
You can use Python's built-in "in" operator. This operator returns True if the item is in the iterable (list in this case), or False if it is not.
x_in_array = x in array
The Python doc that covers this is here, under section 5.6:
https://docs.python.org/2/library/stdtypes.html
Your if/elif/else statements would then look like:
if x in array_1:
# do something
elif x in array_2:
# do something
else:
# do something else
If you want to return the index of the list:
>>> def idx_check(i, l):
... for (idx, val) in enumerate(l):
... if i in val:
... return idx
... return None
...
>>> l = [[1,2,3],[4,5,6],[7,8,9]]
>>> idx_check(1, l)
0
>>> idx_check(4, l)
1
>>> idx_check(7, l)
2
First of all: I know it's just an example, but don't use list as a variable in Python. It is a keyword/built-in function.
Second: you can use iteration to accomplish this. You can iterate through the members of a list (or any iterable object, or any iterator) like this:
for item in L:
# do something with item
You can keep track of the number of times you have entered the loop using the enumerate function. The enumerate function returns a two-tuple in the form of member_index_number, member:
for num,item in enumerate(L):
# do something with num and item
Almost there- now you need a way to associate the above iteration with your list of functions. The usual way this is done in python is with a dictionary, but you could also just use a list.
# list way
funcs_list = [f1, f2, f3]
for num,item in enumerate(L):
if 1 in item:
funcs_list[funcs_list.index(num)]()
break
# dictionary way
funcs_dict = {0: f1, 1: f2, 2: f3}
for num,item in enumerate(L):
if 1 in item:
funcs_dict[num]()
break
The dictionary method is usually preferred because it looks much cleaner.
Than I want to write a function that achieves this purpose, if given:
t = [1,2,[2,2],[3,3]]
I want a function that makes t be
[1,2,4,6]. Here, is my code in Python:
t=[1,2,[2,2],[3,3]]
def nested_sum(t):
for x in t:
if type(t[x])=='int':
t[x]=t[x]
else:
t[x]=['sum(t[x])']
return t
nested_sum(t)
I got the error message that
Traceback (most recent call last):
File "nested_sum.py", line 11, in <module>
nested_sum(t)
File "nested_sum.py", line 5, in nested_sum
if type(t[x])=='int':
TypeError: list indices must be integers, not list
I am not quite sure about the mistake(s) I made. Since my logic is that:
type(t[0])=1 which is of "Int" type and type(t[2])=[2,2] which is of "List" type and I think these fulfills the "if...else..." statement.
Any help would be appreciated for pointing my mistakes. Thank you so much in advance.
You can put it in a single list comprehension using isinstance:
[sum(x) if isinstance(x,list) else x for x in t]
[1, 2, 4, 6]
You could use collection.Iterable which will work on any iterable like tuples etc..
t = [1,2,[2,2],[3,3],(4,5)]
from collections import Iterable
print [sum(x) if isinstance(x, Iterable) else x for x in t]
[1, 2, 4, 6, 9]
In the list comprehension, if x is an iterable/list we add the sum of the subelements or else we just take the element x
Using your own code, you would use enumerate to access the list elements using their index:
def nested_sum(t):
for ind, x in enumerate(t):
if type(t[ind])== int: # int not "int"
t[ind] = x
else:
t[ind] = sum(t[ind])
return t
In the code ind is the index of each subelement and x is the actual subelement
The problem with your code is that you are looping through the items of your list and not through the indexes. For making it work you should change your code like this:
def nested_sum(t):
for x in range(len(t)):
if type(t[x]) == int:
t[x] = t[x]
else:
t[x] = sum(t[x])
return t
Note also that int in type(t[x]) == int and sum(t[x]) in your else clause should not be strings.
Use sum() when x is a list, append it to res otherwise
t=[1,2,[2,2],[3,3]]
def nested_sum(l):
res = []
for x in l:
if type(x) == type([]):
res.append(sum(x))
elif type(x) == type(1):
res.append(x)
return res
nested_sum(t)
def nested_sum(t):
for index, item in enumerate(t):
if type(item) == list:
t[index] = sum(item)
return t
Explanation:
enumerate(t) returns (0, t[0]), (1, t[1]) etc.
Then, for each item in t, check if item is a list. If it is, replace it with the sum of all elements in that list. This is done in t[index] = sum(item).
An answer would be:
def nested_sum(mixed_list):
res = list()
for element in mixed_list:
try:
a = sum(element)
except TypeError:
a = element
res.append(a)
return res
Which works fine if the list contains numbers and lists of numbers.
Basically, I'm trying to flatten a list in my function but ignore that (you can also ignore the print functions I put in).
take x = [[1,2,3],4,5] to be my variable.
I call prob7(x) but the issue is that when type([1,2,3]) gets checked == list, it returns false. Why is that? I explicitly check this on the interpreter command line and it returns true. But inside the function, I get a false.
Just a bug that I missed because I'm sleepy or am I misunderstanding some part of the Python language? I run version 2.6 if it matters.
def prob7(list): # flatten a list
tempList = []
if list: # meaning if there are elements in the list and it is not empty
for i in list:
if type(i) != list:
print tempList,'if',i,type(i)==list
tempList.append(i)
else:
print tempList,'else',i
tempList.extend(prob7(i))
return tempList
Just not use 'list' as a variable name and use isinstance(var, list) instead of type(var) == list.
Please find corrected sample below.
def prob7(mylist): # flatten a list
tempList = []
if mylist: # meaning if there are elements in the list and it is not empty
for i in mylist:
if not isinstance(i, list):
print tempList, 'if', i, isinstance(i, list)
tempList.append(i)
else:
print tempList, 'else', i
tempList.extend(prob7(i))
return tempList
Or if you don't really required to use recursion and you don't care about values order then you can use something like this:
lVals = [[1,2,3],4,5, [1,[4,7]]]
def make_flat(mylist): # flatten a list
while any(isinstance(x, list) for x in mylist):
for i, val in enumerate(mylist):
if isinstance(val, list):
mylist.extend(mylist.pop(i))
break
return mylist
make_flat(lVals)
>>> [4, 5, 1, 2, 3, 1, 4, 7]
Artisom has your answer. In addtion, type checks are not very Pythonic. Duck typing often is the way to go. In case your elements are numbers only, the following does the job too, without explicit type checks but behavior checks:
def prob7(inlist): # flatten a list
outlist = []
for x in inlist:
try:
outlist += x
except TypeError:
outlist.append(x)
return outlist
Note that string elements in this implementation would behave like nested lists. Anyway, just wanted to illustrate what it means to expect behavior, not types.
Some alternate approaches:
# Iterative, but more functional-style
def flatten(a_list):
while any(isinstance(x, list) for x in a_list):
a_list = sum((x if isinstance(x, list) else [x] for x in a_list), [])
return a_list
# Using a generator recursively,
# then evaluating the generator to produce the list
# instead of explicitly appending each element.
def flatten_gen(a_list):
for x in a_list:
if isinstance(x, list):
for y in flatten_gen(x): yield y
else: yield x
def flatten(a_list): return list(flatten_gen(a_list))
The problem here is you are using a local variable name (list) that is the same as the global list type. You should change your variable name. Also, when checking types like that you can use the is operator.
type(l) is list
But here's my version of flatten.
def flatten(alist):
rv = []
for val in alist:
if isinstance(val, list):
rv.extend(flatten(val))
else:
rv.append(val)
return rv
This does not alter the original list, but returns a new list. This is consistent with most other patterns.