This question already has answers here:
Why do these list operations (methods: clear / extend / reverse / append / sort / remove) return None, rather than the resulting list?
(6 answers)
Closed 9 years ago.
I am a beginner to Python, and I was trying to get the below posted Python code to work but unfortunately, it does not give me the expected or the correct result.
I am trying to sort a simple list contains numbers using the built-in method sort() and after executing the program I get NONE as a result.
Please guide me to solve this problem.
Python code
a=[7,4,0,-5,30,2,11,84,6]
b=a.sort()
print(b)
list.sort sorts the list inplace, thus returning None
Instead use the sorted function which returns the sorted list
b = sorted(a)
sort() is an inplace sort. It sorts the list, but doesn't return it (it actually returns None).
>>> a=[7,4,0,-5,30,2,11,84,6]
>>> a.sort()
>>> a
[-5, 0, 2, 4, 6, 7, 11, 30, 84]
To get the sorted list separately, use sorted():
>>> a=[7,4,0,-5,30,2,11,84,6]
>>> b = sorted(a)
>>> b
[-5, 0, 2, 4, 6, 7, 11, 30, 84]
>>> a
[7, 4, 0, -5, 30, 2, 11, 84, 6]
a.sort() sorts a and returns None. Try this:
a=[7,4,0,-5,30,2,11,84,6]
a.sort()
print(a)
The function .sort() do not return a list object it returns None.
If you look at this example you can see how a is sorted without assigning to b.
>>> a=[7,4,0,-5,30,2,11,84,6]
>>> a.sort()
>>> a
[-5, 0, 2, 4, 6, 7, 11, 30, 84]
Related
My mission is to sort the list by the frequency of numbers included in it. If a few numbers have an equal frequency - they should be sorted according to their natural order.
For example: [5, 2, 4, 1, 1, 1, 3] ==> [1, 1, 1, 2, 3, 4, 5]
During the process of solving the problem, I wrote a function as follow:
lista = [3, 4, 11, 13, 11, 4, 4, 7, 3]
def func1(numbers: list):
numbers.sort(key=lambda x:(-numbers.count(x), x))
return numbers
result = func1(lista)
print(result)
but the result is [3, 3, 4, 4, 4, 7, 11, 11, 13],
and then I wrote a function very similar to that
lista = [3, 4, 11, 13, 11, 4, 4, 7, 3]
def func2(numbers: list):
return sorted(numbers,key=lambda x:(-numbers.count(x), x))
result = func2(lista)
print(result)
the result is [4, 4, 4, 3, 3, 11, 11, 7, 13], which is what I wanted
My question is: what's different between list.sort function and sorted function
it is just a few part of my whole homework, please ignore the time complexity of my algorithm.
Because list.sort is an in-place algorithm, the content of the list during its .sort is arbitrary – an algorithm might have the list partially sorted, keep sorted items independently, or even behave differently depending on the "unsortedness". As a result, a key accessing a list during its .sort is not guaranteed to work as expected.
In specific, CPython makes the list appear empty during its .sort:
sort(*, key=None, reverse=False)
CPython implementation detail: While a list is being sorted, the
effect of attempting to mutate, or even inspect, the list is
undefined. The C implementation of Python makes the list appear empty
for the duration, and raises ValueError if it can detect that the list
has been mutated during a sort.
In contrast, sorted guarantees to produce a new list, leaving the old list unmodified and consistent in appearance during sorting.
You can inspect this behaviour by observing the key before using it:
def observe(arg, *hint):
"""Helper to inspect a value during its usage"""
print(repr(arg), *hint)
return arg
numbers = [1, 2, 1]
numbers.sort(key=lambda x: observe(numbers.count(x), "is the key for", x))
# 0 is the key for 1
# 0 is the key for 2
# 0 is the key for 1
sorted(numbers, key=lambda x: observe(numbers.count(x), "is the key for", x))
# 2 is the key for 1
# 1 is the key for 2
# 2 is the key for 1
Using the key function key=lambda x: (-numbers.count(x), x) in .sort means the key is of the form (0, x) – since the first key-part 0 is always equal, items are sorted by the second key-part, i.e. their value. This is equivalent to the standard sort key.
To answer your question about the difference between list.sort() and sorted(list):
They both sort the list you want. But list.sort() changes the original list object (changes the indices) while sorted(list) doesn't effect list itself but. I guess you'd want to create another object from the sorted() function if you didn't want to change the original list. For example, list2 = sorted(list)
This question already has answers here:
Finding and replacing elements in a list
(10 answers)
Closed 2 years ago.
Is there a fancy method for replacing a specific value of a list with another value?
Like a shortcut for this:
>>> l = list(range(10))
>>> replacing = 3
>>> l[l.index(replacing)] = 4
>>> l
[0, 1, 2, 4, 4, 5, 6, 7, 8, 9]
With the example I gave it's easy enough to do via the [l.index()], but when the list reference is a few dots away it starts getting ugly.
It would be so much prettier to do something like this:
>>> some.thing.very.far.away.list = list(range(10))
>>> some.thing.very.far.away.list.replace(3, 4)
Edit:
I forgot to say why.
I want to edit the same list, and only edit one of the values.
I'm actually kind of supprized that lists doesn't have a built-in method like list.replace(old, new[, max), considering that strings do and it seems like python has built-ins for just about everying.
Build a new list with a list comprehension:
new_items = [4 if x==3 else x for x in l]
You can modify the original list in-place if you want, but it doesn't actually save time:
items = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
for index, item in enumerate(items):
if (item ==3 2):
items[index] = 4
you can assign "some.thing.very.far.away.list" to a temporary variable and apply replace function
some.thing.very.far.away.list = temp
something.very.far.away.list = temp.replace(x,y)
This can be a trick:
First define a dictionary with values you want to replace, than use a list comprehension using dictionary get with a default value.
You are passing el both as a key of the dictionary and as default value. If the key is found the corresponding value will be replaced otherwise the default value itself.
>>> l = [0, 1, 2, 4, 4, 5, 6, 7, 8, 9]
>>> rpl = {1: 23, 6: 12}
>>> [rpl.get(el, el) for el in l]
[0, 23, 2, 4, 4, 5, 12, 7, 8, 9]
You can use map method to iterate and replace certain value.
syntax : map(function, iterable, ...)
The returned value from map() (map object) can then be passed to functions like list() (to create a list), set() (to create a set) and so on.
l = list(range(10))
replacing = 3
l = list(map(lambda x: 4 if x == replacing else x, l)) # iterating over list l and replacing certain value using map method and converting map object in to another list.
print(l)
output = [0, 1, 2, 4, 4, 5, 6, 7, 8, 9]
it takes two parameter function and iterable. map() passes each item of the iterable to this function.
where lambda function takes argument x from sequence (l), assign 4 if x is equal to 4 .
to know more about map method Python map()
I tried to create a simple function to remove duplicates from the list.
x = [7, 7, 5, 6, 8, 9, 9, 0]
for n, i in enumerate(x):
if i in x[n + 1:]:
x.remove(i)
print(x)
Output:
[7, 5, 6, 8, 9, 0]
This code works fine as far as I know.
But when I'm trying to convert it in comprehension list form, I'm getting wrong output:
def unique_list(lst):
return [lst.remove(i) for n, i in enumerate(lst) if i in lst[n + 1:]]
x = [7, 7, 5, 6, 8, 9, 9, 0]
print(unique_list(x))
Output:
[None, None]
So, the question is - why the output is different?
a = [1, 2, 3]
deleted = a.remove(1)
print(deleted)
# returns None
print(a)
# returns [2, 3]
.remove() changes the list in place and returns None
Your two ways of writing the functionality of set(x) are not identical. While the first is using a side-effect of x.remove(..) to "return" your modified list in place, the second form returns a newly created list.
The elements of that list are formed by what is returned by the expression lst.remove(i), which is None as Manuel already has pointed out in their answer.
You receive [None, None] because your code calls lst.remove 2 times. So your function unique_list could be called count_duplicates, just with a peculiar output format (with the length of a list of None encoding the result instead of a straightforward int).
This question already has answers here:
Concatenating two range function results
(8 answers)
How can I generate a list of consecutive numbers? [duplicate]
(8 answers)
Closed 3 years ago.
in python is there a way to create of list that will skip numbers and will continue after skipping? something like the following code:
x = [1...3, 6...10]
print(x)
# [1,2,3,6,7,8,9,10]
Well its easy to write a for loop and then skip each defined index/value, or i can just use range, what I am looking for is a shorter more readable line. If not I can understand.
Simplest way to do this is to call range() and unpack result inside list assignment.
x = [*range(1, 4), *range(6, 11)]
Alternatively you can use itertools.chain:
>>> import itertools
>>> list(itertools.chain(range(1, 5), range(20, 25)))
[1, 2, 3, 4, 20, 21, 22, 23, 24]
If numpy is an option, you can use np.r_ to concatenate slice objects:
import numpy as np
np.r_[1:4, 6:11]
# array([ 1, 2, 3, 6, 7, 8, 9, 10])
You can turn it into a recursive function:
def recursive_ranges(ranges):
if len(ranges) == 1:
return list(range(*ranges[0]))
else:
return list(range(*ranges[0])) + recursive_ranges(ranges[1:])
You can then call this, specifying ranges as a list of lists:
ranges = [[1, 4], [6, 11]]
recursive_ranges(ranges)
# [1, 2, 3, 6, 7, 8, 9, 10]
Note the *ranges[0] is used to unpack the elements in ranges[0] into individual arguments. Essentially the recursive function keeps grabbing the first element of ranges, each element of which is a two-element array, and passing those numbers into the range() method as two different values instead of one array. That's what the * does, it unpacks the array. First call, you unpack [1, 4] into range(1, 4) and then append the next call of the recursive function to it.
Basically this unpacks into the following:
list(range(1, 4)) + list(range(6, 11))
but you get to use a much more compact syntax, just passing a list of lists.
I am trying to figure out how to append multiple values to a list in Python. I know there are few methods to do so, such as manually input the values, or put the append operation in a for loop, or the append and extend functions.
However, I wonder if there is a more neat way to do so? Maybe a certain package or function?
You can use the sequence method list.extend to extend the list by multiple values from any kind of iterable, being it another list or any other thing that provides a sequence of values.
>>> lst = [1, 2]
>>> lst.append(3)
>>> lst.append(4)
>>> lst
[1, 2, 3, 4]
>>> lst.extend([5, 6, 7])
>>> lst.extend((8, 9, 10))
>>> lst
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> lst.extend(range(11, 14))
>>> lst
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
So you can use list.append() to append a single value, and list.extend() to append multiple values.
Other than the append function, if by "multiple values" you mean another list, you can simply concatenate them like so.
>>> a = [1,2,3]
>>> b = [4,5,6]
>>> a + b
[1, 2, 3, 4, 5, 6]
If you take a look at the official docs, you'll see right below append, extend. That's what your looking for.
There's also itertools.chain if you are more interested in efficient iteration than ending up with a fully populated data structure.
if the number of items was saved in a variable say n. you can use list comprehension and plus sign for list expansion.
lst = ['A', 'B']
n = 1
new_lst = lst + ['flag'+str(x) for x in range(n)]
print(my_lst)
>>> ['A','B','flag0','flag1']
One way you can work around this type of problem is -
Here we are inserting a list to the existing list by creating a variable new_values.
Note that we are inserting the values in the second index, i.e. a[2]
a = [1, 2, 7, 8]
new_values = [3, 4, 5, 6]
a.insert(2, new_values)
print(a)
But here insert() method will append the values as a list.
So here goes another way of doing the same thing, but this time, we'll actually insert the values in between the items.
a = [1, 2, 7, 8]
a[2:2] = [3,4,5,6]
print(a)