I have a list of lists and I want to learn how to sort the list by the element at index 1 but also sorted by the element at index 2 if index 1 returns the same number for two items.
I want to do this without the use of inbuilt functions and methods so that I can continue to develop my understanding of lists and how to manipulate them.
To recap:
I have a list of lists
Each sublist has the same number of elements
I am trying to sort them in descending order by creating a new unsorted list which is a copy of the original list (I don't want to modify the original unsorted list) and looping over the copy of the unsorted list to grab the highest number in (from index 1) and then appending that to a newly created sorted_lists variable
I then remove that list from the original unsorted list
I repeat the process until one by one the remaining lists with the highest value is added to the new sorted list and removed from the original list
I have tried a few different things but cannot get it to work. Any help would be appreciated.
# initialising list
food_list = (
["banana", 10, "f", "yellow"],
["apple", 12, "f", "red"],
["pear", 60, "f", "green"],
["mango", 5, "f", "yellow"],
["lettuce", 3, "v", "green"],
["beans", 20, "v", "green"],
["red capsicum", 1, "v", "red"],
["corn", 20, "v", "yellow"],
)
unsorted_food_list_copy = food_list
sorted_food_list = []
while len(unsorted_food_list_copy) != 0:
maximum = 0
for food in unsorted_food_list_copy:
if food[1] > maximum:
maximum = food[1]
sorted_food_list.append(maximum)
unsorted_food_list_copy.remove(maximum)
I have also tried this:
# initialising list
food_list = (
["banana", 10, "f", "yellow"],
["apple", 12, "f", "red"],
["pear", 60, "f", "green"],
["mango", 5, "f", "yellow"],
["lettuce", 3, "v", "green"],
["beans", 20, "v", "green"],
["red capsicum", 1, "v", "red"],
["corn", 20, "v", "yellow"],
)
unsorted_food_list_copy = food_list
sorted_food_list = []
while unsorted_food_list_copy:
min = unsorted_food_list_copy[1]
for x in unsorted_food_list_copy:
if x < min:
min = x
sorted_food_list.append(min)
unsorted_food_list_copy.remove(min)
In your code sample, you define food_list as a tuple while mentioning a list of list. In order to use list function like remove, copy or append, you need to add brackets around your lists.
Firstly, your food_list should be defined this way :
food_list = [
['banana', 10, 'f', 'yellow'],
['apple', 12, 'f', 'red'],
['pear', 60, 'f', 'green'],
['mango', 5, 'f', 'yellow'],
['lettuce', 3, 'v', 'green'],
['beans', 20, 'v', 'green'],
['red capsicum', 1, 'v', 'red'],
['corn', 20, 'v', 'yellow'],
]
Secondly you set up your minimum value before iterating over the list, you consider the 1st element of your list in order to start looking for a lower integer.
minValue = unsorted_food_list_copy[0]
Complete solution :
# initializing list
food_list = [
['banana', 10, 'f', 'yellow'],
['apple', 12, 'f', 'red'],
['pear', 60, 'f', 'green'],
['mango', 5, 'f', 'yellow'],
['lettuce', 3, 'v', 'green'],
['beans', 20, 'v', 'green'],
['red capsicum', 1, 'v', 'red'],
['corn', 20, 'v', 'yellow'],
]
unsorted_food_list_copy = food_list.copy()
sorted_food_list = []
for i in range(len(unsorted_food_list_copy)):
minValue = unsorted_food_list_copy[0]
for x in unsorted_food_list_copy:
if x[1] < minValue[1]:
minValue = x
sorted_food_list.append(minValue)
unsorted_food_list_copy.remove(minValue)
sorted_food_list_descending = sorted_food_list[::-1]
print(sorted_food_list_descending)
# Ouput
[['pear', 60, 'f', 'green'],
['corn', 20, 'v', 'yellow'],
['beans', 20, 'v', 'green'],
['apple', 12, 'f', 'red'],
['banana', 10, 'f', 'yellow'],
['mango', 5, 'f', 'yellow'],
['lettuce', 3, 'v', 'green'],
['red capsicum', 1, 'v', 'red']]
To do this in descending order you could do this:
food_list = [
['banana', 10, 'f', 'yellow'],
['apple', 12, 'f', 'red'],
['pear', 60, 'f', 'green'],
['mango', 5, 'f', 'yellow'],
['lettuce', 3, 'v', 'green'],
['beans', 20, 'v', 'green'],
['red capsicum', 1, 'v', 'red'],
['corn', 20, 'w', 'yellow'],
]
food_list_copy = food_list.copy()
new_list = []
while food_list_copy:
hi = food_list_copy[0]
pi = 0
for i, e in enumerate(food_list_copy[1:], 1):
if e[1] > hi[1]:
hi = e
pi = i
elif e[1] == hi[1]:
if e[2] > hi[2]:
hi = e
pi = i
new_list.append(hi)
food_list_copy.pop(pi)
print(new_list)
Output:
[['pear', 60, 'f', 'green'],
['corn', 20, 'w', 'yellow'],
['beans', 20, 'v', 'green'],
['apple', 12, 'f', 'red'],
['banana', 10, 'f', 'yellow'],
['mango', 5, 'f', 'yellow'],
['lettuce', 3, 'v', 'green'],
['red capsicum', 1, 'v', 'red']]
The pythonic way to sort a list according to a specify (user-defined) key is to use sort with the key parameter.
food_list = [
["banana", 10, "f", "yellow"],
["apple", 12, "f", "red"],
["pear", 60, "f", "green"],
["mango", 5, "f", "yellow"],
["lettuce", 3, "v", "green"],
["beans", 20, "v", "green"],
["red capsicum", 1, "v", "red"],
["corn", 20, "w", "yellow"],
]
# create a copy (you can also use `copy.deepcopy`) and sort
sorted_food_list = [list(i) for i in food_list]
sorted_food_list.sort(key=lambda i: (-i[1], i[2]))
output
[['pear', 60, 'f', 'green'],
['beans', 20, 'v', 'green'],
['corn', 20, 'w', 'yellow'],
['apple', 12, 'f', 'red'],
['banana', 10, 'f', 'yellow'],
['mango', 5, 'f', 'yellow'],
['lettuce', 3, 'v', 'green'],
['red capsicum', 1, 'v', 'red']]
How is it possible to define own _id in couchdb-python (0.9), because when I tried '_id': i[5] I got the following error message?
$ python test3.py
828288
Traceback (most recent call last):
File "test3.py", line 42, in <module>
db.save(doc)
File "/home/mictadlo/.virtualenvs/unisnp/lib/python2.7/site-packages/couchdb/client.py", line 415, in save
func = _doc_resource(self.resource, doc['_id']).put_json
File "/home/mictadlo/.virtualenvs/unisnp/lib/python2.7/site-packages/couchdb/client.py", line 954, in _doc_resource
if doc_id[:1] == '_':
TypeError: 'int' object has no attribute '__getitem__'
Below is the script which is causing the above error:
from couchdb.mapping import Document, TextField, IntegerField, Mapping
from couchdb.mapping import DictField, ViewField, BooleanField, ListField
from couchdb import Server
# $ sudo systemctl start couchdb
# http://localhost:5984/_utils/
server = Server()
db = server.create("test")
r = [["Test", "A", "B01", 828288, 1, 7, 'C', 5],
["Test", "A", "B01", 828288, 1, 7, 'T', 6],
["Test", "A", "B01", 171878, 3, 8, 'C', 5],
["Test", "A", "B01", 171878, 3, 8, 'T', 6],
["Test", "A", "B01", 871963, 3, 9, 'A', 5],
["Test", "A", "B01", 871963, 3, 9, 'G', 6],
["Test", "A", "B01", 1932523, 1, 10, 'T', 4],
["Test", "A", "B01", 1932523, 1, 10, 'A', 5],
["Test", "A", "B01", 1932523, 1, 10, 'X', 6],
["Test", "A", "B01", 667214, 1, 14, 'T', 4],
["Test", "A", "B01", 667214, 1, 14, 'G', 5],
["Test", "A", "B01", 667214, 1, 14, 'G', 6]]
for i in r:
print i[3]
doc = {
'type': i[0],
'name': i[1],
'sub_name': i[2],
'pos': i[3],
's_type': i[4],
'_id': i[5],
'chr':[]
}
doc['chr'].append({
"letter":i[6],
"no":i[7]
})
db.save(doc)
It expects _id to be a string and you are passing a type of int. The error is caused by this line:
if doc_id[:1] == '_':
Because script is trying to slice an int object.
So change it to string type:
...
...
'_id': str(i[5]),
...
I want to replace the value of first key of list1 with the elements of list2. But the output with following code is:
output
list[21, 21, 22, 22]
[{'a': array([[22, 22, 3]]), 'i': 'stop', 'c': array([7, 8, 9]), 'b': array([4, 5, 6])}, {'a': array([[1, 2, 3]]), 'i': 'stop', 'c': array([7, 8, 9]), 'b': array([4, 5, 6])}]
my code
list1 = [{'a': array([(1,2,3)]), 'b': array([4,5,6]), 'i': 'stop', 'c': array([7,8,9])}, {'a': array([(1,2,3)]), 'b': array([4,5,6]), 'i': 'stop', 'c': array([7,8,9])}]
list2 = [ array([21, 22, 23]), array([25, 26, 27])]
list3=[]
for item in liste:
for key,value in item.iteritems():
if key == 'a':
list3.append(value)
list4=[]
for i in range(len(g_a)):
for j in range(len(list3)):
list3[0][0][j] = g_a[0][i]
list4.append(list3[0][0][j])
print list4
print list
I want to get this:
liste = [{'a': array([(21,22,23)]), 'b': array([4,5,6]), 'i': 'stop', 'c': array([7,8,9])}, {'a': array([(25,26,27)]), 'b': array([4,5,6]), 'i': 'stop', 'c': array([7,8,9])}]
Where is the error? Thank you very much in advance!
Here is a dict comprehension in python 2.7 with a one-liner:
[{k: d[k] if k != 'a' else list2[i] for k in d} for i, d in enumerate(list1)]
It gives:
[{'a': [21, 22, 23], 'i': 'stop', 'c': [7, 8, 9], 'b': [4, 5, 6]}, {'a': [25, 26, 27], 'i': 'stop', 'c': [7, 8, 9], 'b': [4, 5, 6]}]
It seems they are behaving exactly the same way.
>>> data
[('a', 'b'), {'a': 1, 'b': 2}, ['a', 'b'], 'a', 'b']
>>> json.dumps(data)
'[["a", "b"], {"a": 1, "b": 2}, ["a", "b"], "a", "b"]'
>>> tornado.escape.json_encode(data)
'[["a", "b"], {"a": 1, "b": 2}, ["a", "b"], "a", "b"]'
>>> json.loads(json.dumps(data))
[[u'a', u'b'], {u'a': 1, u'b': 2}, [u'a', u'b'], u'a', u'b']
>>> tornado.escape.json_decode(json.dumps(data))
[[u'a', u'b'], {u'a': 1, u'b': 2}, [u'a', u'b'], u'a', u'b']
Sometimes it's useful to read the source code:
def json_encode(value):
return json.dumps(value).replace("</", "<\\/")
def json_decode(value):
return json.loads(to_basestring(value))
def to_basestring(value):
if isinstance(value, _BASESTRING_TYPES):
return value
assert isinstance(value, bytes_type)
return value.decode("utf-8")
to_basestring is mostly needed for python 3.x to ensure the value has type str, not bytes, because json.loads can't deal with the latter.