Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

F# sort by indexes

Tags:

f#

Let's say I have two lists:

let listOfValues = [100..105]   //can be list of strings or whatever
let indexesToSortBy = [1;2;0;4;5;3]

Now I need listOfValues_sorted: 102;100;101;105;103;104

It can be done with zip and "conversion" to Tuple:

let listOfValues_sorted = listOfValues 
                        |> Seq.zip indexesToSortBy
                        |> Seq.sortBy( fun x-> fst x)
                        |> Seq.iter(fun c ->  printfn "%i" (snd c))

But I guess, there is better solution for that?

like image 224
Alamakanambra Avatar asked Feb 13 '17 14:02

Alamakanambra


3 Answers

I think your solution is pretty close. I would do this

let listOfValues_sorted = 
    listOfValues 
    |> Seq.zip indexesToSortBy
    |> Seq.sortBy fst
    |> Seq.toList
    |> List.unzip
    |> List.head

you can collapse fun x -> fst x into simply fst. And then unzip and get what ever list you want

like image 137
robkuz Avatar answered Oct 20 '22 03:10

robkuz


If indexesToSortBy is a complete set of indexes you could simply use:

indexesToSortBy |> List.map (fun x -> listOfValues |> List.item x )
like image 32
Stuart Avatar answered Oct 20 '22 03:10

Stuart


Your example sounds precisely what the List.permute function is for:

let listOfValues = [100..105]
let indexesToSortBy = [|1;2;0;4;5;3|]  // Note 0-based indexes

listOfValues |> List.permute (fun i -> indexesToSortBy.[i])
// Result: [102; 100; 101; 105; 103; 104]

Two things: First, I made indexesToSortBy an array since I'll be looking up a value inside it N times, and doing that in a list would lead to O(N^2) run time. Second, List.permute expects to be handed a 0-based index into the original list, so I subtracted 1 from all the indexes in your original indexToSortBy list. With these two changes, this produces exactly the same ordering as the let listOfValues_sorted = ... example in your question.

like image 3
rmunn Avatar answered Oct 20 '22 01:10

rmunn