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);
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.
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.
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
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.