Python - Print items from a dict sorted by value - sorting

Here is a dict of pets and how many of them.
{"Birds" : 2, "Cats" : 3, "Dogs" : 4}
I want to print the items sorted by largest number of the same pet to the smallest number of the same pet, or vice versa.
Desired output:
('Dogs', 4)
('Cats', 3)
('Birds', 2)
And
('Birds', 2)
('Cats', 3)
('Dogs', 4)
How could this be done?
I do not want to import anything.

with lambda expression x[1] stands for values, x[0] for keys in key-value pair from a dictionary.
sorted(d.items(), key=lambda x: x[1], reverse=True)
sorted(d.items(), key=lambda x: x[0])
without lambda expr, operator.itemgetter does the same thing:
from operator import itemgetter
sorted(d.items(), key=itemgetter(1), reverse=True)
sorted(d.items(), key=itemgetter(0))

Using the built-in sorted function with a special ranking function and a reverse=True argument:
for item in sorted(dict.items(), key=lambda x: x[1], reverse=True):
print(item)
A key of lambda x: -x[1] should also work (without reverse argument).

For purposes of understanding from a beginners point of view sometimes it is better to write more code to achieve this.
As dictionaries cannot be sorted, you can take each key and value pair and return a list with a simple function.
mydict = {"Birds" : 2, "Cats" : 3, "Dogs" : 4}
def sortDict(dictionary):
sorted_values = sorted(dictionary.values())
sorted_keys = sorted(dictionary.keys())
#sorted_values.reverse()
#sorted_keys.reverse()
for key, value in zip(sorted_keys, sorted_values):
print(key, value)
sortDict(mydict)
Simply remove the # characters to reverse the result.

Related

Optimal way to index a list of numbers

Given a list of non-sequential and unordered numbers is there an optimal means to index the list, where the ith element in the index is the position of the ith element in the indexed list if it were sorted.
So [45,2,6,33] would have index [4,1,2,3]
You can just sort the list and then create a dictionary / associative array mapping each element to its index in the sorted list. You could do this in a loop, or, in Python, even in a single line:
>>> lst = [45, 2, 6, 33]
>>> d = {x: i for (i, x) in enumerate(sorted(lst))}
>>> d
{2: 0, 6: 1, 33: 2, 45: 3}
Now use the values from the dictionary to create your result list:
>>> [d[x] + 1 for x in lst]
[4, 1, 2, 3]
If the list can contain duplicate numbers, and you don't want your result list to contain duplicate indices, you can map the values to lists of indices:
>>> lst = [45, 2, 6, 33, 6]
>>> d = {}
>>> for i, x in enumerate(sorted(lst)):
... d.setdefault(x, []).append(i)
>>> d
{2: [0], 6: [1, 2], 33: [3], 45: [4]}
Now, convert each of those lists to an iterator, and get the next index for each value in the original list.
>>> d2 = {x: iter(d[x]) for x in d}
>>> [next(d2[x]) + 1 for x in lst]
[5, 1, 2, 4, 3]
You can perform radix sort which uses counting sort as a sub-routine and can work in linear time complexity for large numbers as well. Time complexity will be O(n).
Then use a hashmap <element, position when sorted> to record the position of the elements in sorted list. At last print the corresponding position of input. Space complexity is O(n).
It seems that the problem you are facing is that how to keep the original position of element since after sorting the position would be lost. You need to link position in original array with the element and then sort. Following is the pseudo code
list of pair p[] as (element, original position)
for each index i in original input array A
p.push(A[i], i) //adding element and original position
Sort on basis of first element
q = sort(p)
Now q has element in its position after sorting. Second array should have this position on its index in original array
Let new array B is resultant array
for each index i in array q
B[q[i].second] = i //q[i].second is index in original array. so putting index of sorted array in that
Update: Some are not able to understand this algorithm so have put a code in JavaScript.
var input = [45,2,6,33];
var p = [];
for(var i = 0;i < input.length;i++)
{
p.push({first:input[i],second:i});
}
p.sort(function(a,b){
return a.first > b.first;
});
var B = Array(input.length);
for(var i = 0;i < p.length;i++)
{
B[p[i].second] = i;
}
console.log(B);

Scala : Sorting list of number based on another list

I am implementing an algorithm in scala where I have set of nodes (Integers numbers) and each node has one property associated with it, lets call that property "d" (which is again an integer).
I have a list[Int] , this list contains nodes in the descending order of value "d".
Also I have a Map[Int,Iterable[Int]] , here key is a node and value is the list of all its neighbors.
The question is, how can I store the List of neighbors for a node in Map in the descending order of property "d" .
Example :
List 1 : List[1,5,7,2,4,8,6,3] --> Imagine this list is sorted in some order and has all the numbers.
Map : [Int,Iterable][Int]] --> [1 , Iterable[2,3,4,5,6]]
This iterable may or may not have all numbers.
In simple words, I want the numbers in Iterable to be in same order as in List 1.
So my entry in Map should be : [1, Iterable[5,2,4,6,3]]
The easiest way to do this is to just filter the sorted list.
val list = List(1,5,7,2,4,8,6,3)
val map = Map(1 -> List(2,3,4,5,6),
2 -> List(1,2,7,8))
val map2 = map.mapValues(neighbors => list.filter(neighbors.contains))
println(map2)
Here is a possible solution utilizing foldLeft (note we get an ArrayBuffer at end instead of desired Iterable, but the type signature does say Iterable):
scala> val orderTemplate = List(1,5,7,2,4,8,6,3)
orderTemplate: List[Int] = List(1, 5, 7, 2, 4, 8, 6, 3)
scala> val toOrder = Map(1 -> Iterable(2,3,4,5,6))
toOrder: scala.collection.immutable.Map[Int,Iterable[Int]] = Map(1 -> List(2, 3, 4, 5, 6))
scala> val ordered = toOrder.mapValues(iterable =>
orderTemplate.foldLeft(Iterable.empty[Int])((a, i) =>
if (iterable.toBuffer.contains(i)) a.toBuffer :+ i
else a
)
)
ordered: scala.collection.immutable.Map[Int,Iterable[Int]] = Map(1 -> ArrayBuffer(5, 2, 4, 6, 3))
Here's what I got.
val lst = List(1,5,7,2,4,8,6,3)
val itr = Iterable(2,3,4,5,6)
itr.map(x => (lst.indexOf(x), x))
.toArray
.sorted
.map(_._2)
.toIterable // res0: Iterable[Int] = WrappedArray(5, 2, 4, 6, 3)
I coupled each entry with its relative index in the full list.
Can't sort iterables so went with Array (for no particular reason).
Tuples sorting defaults to the first element.
Remove the indexes.
Back to Iterable.

Array insert and shift

I have the below array:
a = [0, 1, 2, 3, 4, nil, nil]
And I'd like to insert an element num into index 2 such that the resulting array is:
a = [0, 1, num, 2, 3, 4, nil] # note the size hasn't changed
I realize an Array might not be the most suitable data structure for this exercise, but assume that's a requirement.
How can I do this?
Why?
I'm trying to solve this problem:
You are given two sorted arrays, A and B, where A has a large enough buffer at the end to hold B. Write a method to merge B into A in sorted order
Here's my code so far:
def merge(a, b) # merge b -> a
pointer = 0 # on a
while !b.empty? do
case b.first <=> a[pointer]
when 0, 1 next
when -1
# insert element, shift array to the right
end
end
end
Is this what you are looking for?
a.insert(2, num)
Not sure if you looking to manually shift the elements, but this should do all of the work for you.

Reduce all values to one specified

So I have a group of lists which looks like:
[['Amy,1,"10,10,6"'], ['Bella,3,"4,7,2"'], ['Cendrick,3,"5,1,9"'], ['Fella,2,"3,8,4"'], ['Hussain,1,"9,4,3"'], ['Jamie,2,"1,1,1"'], ['Jack,3,"10,8,0"'], ['Thomas,2,"5,0,5"'], ['Zyra,1,"7,8,7"']]
Whereby the number after the name is the student's class number and the following 3 numbers are the 3 scores which that student scored.
I have sorted it from an organised group of lists to this alphabetical one however I am having difficulty with the following:
I want to be able to sort them alphabetically but only for a specific class and the highest score out of the last three values. For example, if I wanted to sort class 2, then the output would be as follows:
Fella,8
Jamie,1
Thomas,5
As the names have been sorted alphabetically and all students are from class 2. Each students high score has also been placed beside them.
I would really appreciate any help. TIA
Your data structure is way off. It looks like you wanted to hold information about each student in a list, but ended up putting just one comma delimited string with that information in that list. You then ended up with a list of lists, each of which contained one such string.
This is really what you wanted to do:
[[Amy, 1, 10,10,6],
[Bella, 3, 4,7,2],
[Cendrick, 3, 5,1,9],
[Fella, 2, 3,8,4],
[Hussain, 1, 9,4,3],
[Jamie, 2, 1,1,1],
[Jack, 3, 10,8,0],
[Thomas, 2, 5,0,5],
[Zyra, 1, 7,8,7]
]
Here's how you transform what you have, into what you wanted:
students = []
for student in myList: # myList is the list that you already have
s = []
name, course, grades = student[0].split(',', 2)
s.append(name)
s.append(int(course))
s.extend([int(i) for i in grades.strip('"').split(',')])
students.append(s)
Once you have this, then you can filter and sort students as follows:
import operator
classNum = 1 # let's say you want all the students from class number 1
answer = sorted([s for s in students if s[1]==classNum], key=operator.itemgetter(0))
for student in answer:
name = student[0]
grade = max(student[2:]))
print(name, grade)
Note that I said that this is what it seems like you wanted to do. In your position, this is what I would do:
from collections import namedtuple as ntuple
Student = ntuple('Student', ['name', 'course', 'grades'])
students = []
courseNum = 1
for student in myList: # myList is the list that you already have
s = Student
name, course, grades = student[0].split(',', 2)
course = int(course)
if course != courseNum: continue
grades = [int(i) for i in grades.strip('"').split(',')]
students.append(Student(name, course, grades))
students.sort(key=operator.attrgetter('name'))
for student in students:
print(student.name, max(student.grades))
Maybe this would work:
def transform(inputs, class_number):
results = []
for input in inputs:
input = input[0]
input_pieces = input.split(',', 2)
if input_pieces[1] != class_number:
continue
scores = input_pieces[2].strip('"').split(',')
results.append((input_pieces[0], max(scores)))
return results
Also, I strongly recommend you use something to give your data a little more structure than just a comma-separated string. Something like collections.namedtuple. Then you could have a list of namedtuple's with meaningfully named fields.
Below is the solution, with the way you've your data stored at the moment -- makes processing hard.
>>> lst = [['Amy,1,"10,10,6"'], ['Bella,3,"4,7,2"'], ['Cendrick,3,"5,1,9"'],
['Fella,2,"3,8,4"'], ['Hussain,1,"9,4,3"'], ['Jamie,2,"1,1,1"'], ['Jack,3,"10,8,0"'], ['Thomas,2,"5,0,5"'], ['Zyra,1,"7,8,7"']]
>>> from itertools import chain
>>> lst_flat = chain.from_iterable(lst)
>>> sorted_lst = sorted(filter(lambda x: x.split(',')[1] == '2', lst_flat))
>>> print map(lambda x: (x.split(',')[0],
max([int(y) for y in x.split('"')[1].split(',')])), sorted_lst)
[('Fella', 8), ('Jamie', 1), ('Thomas', 5)]
You should consider cleaning up the way you've represented your data:
>>> from pprint import pprint
>>> from itertools import chain
>>> lst_clean = []
>>> for item in chain.from_iterable(lst):
... name, cls = item.split(',')[0], item.split(',')[1]
... marks = [int(x) for x in item.split('"')[1].split(',')]
... lst_clean.append((name, cls, marks))
>>> pprint(lst_clean)
[('Amy', '1', [10, 10, 6]),
('Bella', '3', [4, 7, 2]),
('Cendrick', '3', [5, 1, 9]),
('Fella', '2', [3, 8, 4]),
('Hussain', '1', [9, 4, 3]),
('Jamie', '2', [1, 1, 1]),
('Jack', '3', [10, 8, 0]),
('Thomas', '2', [5, 0, 5]),
('Zyra', '1', [7, 8, 7])]
>>> sorted_lst = sorted([(name, cls, marks) for (name, cls, marks) in lst_clean if cls == '2'])
>>> for name, cls, marks in sorted_lst:
... print name, max(marks)
Fella 8
Jamie 1
Thomas 5

How do I filter elements in an array?

Sample Array:
x = [1,2,3,4,2,2,2]
Filter:
y = [2,4,7,9]
Desired output:
result = [2,4,2,2,2]
I tried:
result = (x & y)
but this gives me [4,2].
How do I get: result = [2,4,2,2,2]?
How about:
x - (x - y)
#=> [2, 4, 2, 2, 2]
1-2 lines longer than #Mark's answer, but more efficient (if both arrays are large):
require 'set'
keep = Set[2,4,7,9] # or Set.new(some_large_array)
result = x.select{ |n| keep.include?(n) } #=> [2, 4, 2, 2, 2]
The problem with writing...
x.select{ |i| y.include?(i) }
...is that this is O(x*y) the the number of elements in each array. With 100 elements in each you are doing 10,000 operations in the worst case; my answer does only 100 operations.
First, don't capitalize variables in Ruby. Capitalization is for constants, like class names.
result = x.select {|i| y.include? i}
Note that select is also called find_all, and is the positive filter in ruby; the negative filter is reject. Between the braces you can put any code you want; it will be run once for each item of x (the item is passed in as an argument and becomes i), and the result of the whole call will include all the elements for which the block returns a true value.

Resources