Order and ranking
Sometimes you need the order of your data rather than the sorted data itself: to reorder several columns the same
way, to rank players, or to sort a table by more than one column. This page covers argsort, rank and the
multi-column calls.
The order of an array: argsort
argsort(a) returns the positions that would sort a. The first entry is the position of the smallest value, the
next one the position of the second smallest, and so on. a is not changed.
import numpy as np
import kwker
price = np.array([4.99, 1.25, 9.50, 2.75])
order = kwker.argsort(price)
print(order)
print(price[order])
[1 3 0 2]
[1.25 2.75 4.99 9.5 ]
use kwker::Order;
fn main() {
let price = [4.99, 1.25, 9.50, 2.75];
let order: Vec<usize> = kwker::argsort(&price, Order::ASCENDING);
let sorted: Vec<f64> = order.iter().map(|&i| price[i]).collect();
println!("{order:?}");
println!("{sorted:?}");
}
[1, 3, 0, 2] [1.25, 2.75, 4.99, 9.5]
#include <inttypes.h>
#include <stdio.h>
#include <kwker.h>
int main(void) {
const double price[] = {4.99, 1.25, 9.50, 2.75};
uint64_t order[4];
kwker_f64_argsort(price, 4, KWKER_ASCENDING, order);
for (int i = 0; i < 4; i++) printf(i ? " %" PRIu64 : "%" PRIu64, order[i]);
printf("\n");
for (int i = 0; i < 4; i++) printf(i ? " %g" : "%g", price[order[i]]);
printf("\n");
return 0;
}
1 3 0 2 1.25 2.75 4.99 9.5
#include <iostream>
#include <vector>
#include <kwker.hpp>
int main() {
std::vector<double> price{4.99, 1.25, 9.50, 2.75};
std::vector<uint64_t> order = kwker::argsort(price);
for (auto i : order) std::cout << i << ' ';
std::cout << '\n';
for (auto i : order) std::cout << price[i] << ' ';
std::cout << '\n';
}
1 3 0 2 1.25 2.75 4.99 9.5
const kwk = require("kwker");
const price = new Float64Array([4.99, 1.25, 9.50, 2.75]);
const order = kwk.argsort(price);
console.log(order);
console.log(Array.from(order, (i) => price[i]));
Uint32Array(4) [ 1, 3, 0, 2 ]
[ 1.25, 2.75, 4.99, 9.5 ]
package main
import (
"fmt"
"kwker.io/go/kwker"
)
func main() {
price := []float64{4.99, 1.25, 9.50, 2.75}
order := kwker.Argsort(price, kwker.Ascending)
fmt.Println(order)
for _, i := range order {
fmt.Print(price[i], " ")
}
fmt.Println()
}
[1 3 0 2] 1.25 2.75 4.99 9.5
import io.kwker.Kwker;
import java.util.Arrays;
public class Example {
public static void main(String[] args) {
double[] price = {4.99, 1.25, 9.50, 2.75};
int[] order = Kwker.argsort(price, Kwker.ASCENDING);
System.out.println(Arrays.toString(order));
System.out.println(Arrays.toString(Arrays.stream(order).mapToDouble(i -> price[i]).toArray()));
}
}
[1, 3, 0, 2] [1.25, 2.75, 4.99, 9.5]
using Kwker;
var price = new double[] { 4.99, 1.25, 9.50, 2.75 };
var order = Sorter.ArgSort<double>(price);
Console.WriteLine(string.Join(" ", order));
Console.WriteLine(string.Join(" ", order.Select(i => price[i])));
1 3 0 2 1.25 2.75 4.99 9.5
argsort is stable: equal values keep their original order. That matters as soon as you use the order for other
data.
Reorder several columns together
Sort one array and apply the same order to the others. Here, a table of people is sorted by age. Ben and Dara are both 27 and stay in their original order.
import numpy as np
import kwker
name = np.array(["Ana", "Ben", "Chen", "Dara", "Eli"])
age = np.array([34, 27, 41, 27, 30])
city = np.array(["Oslo", "Lima", "Kyiv", "Pune", "Rome"])
order = kwker.argsort(age)
for n, a, c in zip(name[order], age[order], city[order]):
print(n, a, c)
Ben 27 Lima
Dara 27 Pune
Eli 30 Rome
Ana 34 Oslo
Chen 41 Kyiv
use kwker::Order;
fn main() {
let name = ["Ana", "Ben", "Chen", "Dara", "Eli"];
let age = [34, 27, 41, 27, 30];
let city = ["Oslo", "Lima", "Kyiv", "Pune", "Rome"];
let order: Vec<usize> = kwker::argsort(&age, Order::ASCENDING);
for i in order {
println!("{} {} {}", name[i], age[i], city[i]);
}
}
Ben 27 Lima Dara 27 Pune Eli 30 Rome Ana 34 Oslo Chen 41 Kyiv
#include <stdio.h>
#include <kwker.h>
int main(void) {
const char* name[] = {"Ana", "Ben", "Chen", "Dara", "Eli"};
const int32_t age[] = {34, 27, 41, 27, 30};
const char* city[] = {"Oslo", "Lima", "Kyiv", "Pune", "Rome"};
uint64_t order[5];
kwker_i32_argsort(age, 5, KWKER_ASCENDING, order);
for (int j = 0; j < 5; j++) {
uint64_t i = order[j];
printf("%s %d %s\n", name[i], age[i], city[i]);
}
return 0;
}
Ben 27 Lima Dara 27 Pune Eli 30 Rome Ana 34 Oslo Chen 41 Kyiv
#include <iostream>
#include <string>
#include <vector>
#include <kwker.hpp>
int main() {
std::vector<std::string> name{"Ana", "Ben", "Chen", "Dara", "Eli"};
std::vector<int> age{34, 27, 41, 27, 30};
std::vector<std::string> city{"Oslo", "Lima", "Kyiv", "Pune", "Rome"};
for (auto i : kwker::argsort(age)) std::cout << name[i] << ' ' << age[i] << ' ' << city[i] << '\n';
}
Ben 27 Lima Dara 27 Pune Eli 30 Rome Ana 34 Oslo Chen 41 Kyiv
const kwk = require("kwker");
const name = ["Ana", "Ben", "Chen", "Dara", "Eli"];
const age = new Int32Array([34, 27, 41, 27, 30]);
const city = ["Oslo", "Lima", "Kyiv", "Pune", "Rome"];
for (const i of kwk.argsort(age)) console.log(name[i], age[i], city[i]);
Ben 27 Lima
Dara 27 Pune
Eli 30 Rome
Ana 34 Oslo
Chen 41 Kyiv
package main
import (
"fmt"
"kwker.io/go/kwker"
)
func main() {
name := []string{"Ana", "Ben", "Chen", "Dara", "Eli"}
age := []int32{34, 27, 41, 27, 30}
city := []string{"Oslo", "Lima", "Kyiv", "Pune", "Rome"}
for _, i := range kwker.Argsort(age, kwker.Ascending) {
fmt.Println(name[i], age[i], city[i])
}
}
Ben 27 Lima Dara 27 Pune Eli 30 Rome Ana 34 Oslo Chen 41 Kyiv
import io.kwker.Kwker;
public class Example {
public static void main(String[] args) {
String[] name = {"Ana", "Ben", "Chen", "Dara", "Eli"};
int[] age = {34, 27, 41, 27, 30};
String[] city = {"Oslo", "Lima", "Kyiv", "Pune", "Rome"};
for (int i : Kwker.argsort(age, Kwker.ASCENDING)) System.out.println(name[i] + " " + age[i] + " " + city[i]);
}
}
Ben 27 Lima Dara 27 Pune Eli 30 Rome Ana 34 Oslo Chen 41 Kyiv
using Kwker;
var name = new[] { "Ana", "Ben", "Chen", "Dara", "Eli" };
var age = new int[] { 34, 27, 41, 27, 30 };
var city = new[] { "Oslo", "Lima", "Kyiv", "Pune", "Rome" };
foreach (var i in Sorter.ArgSort<int>(age)) Console.WriteLine($"{name[i]} {age[i]} {city[i]}");
Ben 27 Lima Dara 27 Pune Eli 30 Rome Ana 34 Oslo Chen 41 Kyiv
Ask for a descending order to get the largest first. Equal values still keep their original order.
Ranks
rank(a) gives each value its rank, starting at 1. Equal values need a rule, and the method chooses it:
| method | Equal values get | Same as |
|---|---|---|
"average" (Python's default) |
the mean of their ranks | scipy.stats.rankdata |
"min" |
the lowest of their ranks | SQL RANK() |
"max" |
the highest of their ranks | |
"dense" |
the same rank, with no gaps after | SQL DENSE_ |
"ordinal" |
different ranks, in their original order | SQL ROW_ |
In Rust the methods are RankTies::Min, Max, Dense and Ordinal (and rank_average); in C the ties argument
0 (ordinal), 1 (min), 2 (max) or 3 (dense), and kwker_<t>_rank_f64 for the average; in C++
kwker::Ties and rank_average.
import numpy as np
import kwker
points = np.array([10, 20, 20, 30])
for method in ["average", "min", "max", "dense", "ordinal"]:
print(f"{method:8}", kwker.rank(points, method=method))
average [1. 2.5 2.5 4. ]
min [1 2 2 4]
max [1 3 3 4]
dense [1 2 2 3]
ordinal [1 2 3 4]
use kwker::{Order, RankTies};
fn main() {
let points = [10, 20, 20, 30];
println!("average {:?}", kwker::rank_average(&points, Order::ASCENDING));
for (name, ties) in [("min", RankTies::Min), ("max", RankTies::Max), ("dense", RankTies::Dense), ("ordinal", RankTies::Ordinal)] {
println!("{name:8} {:?}", kwker::rank(&points, Order::ASCENDING, ties));
}
}
average [1.0, 2.5, 2.5, 4.0] min [1, 2, 2, 4] max [1, 3, 3, 4] dense [1, 2, 2, 3] ordinal [1, 2, 3, 4]
#include <inttypes.h>
#include <stdio.h>
#include <kwker.h>
int main(void) {
const int32_t points[] = {10, 20, 20, 30};
double average[4];
kwker_i32_rank_f64(points, 4, KWKER_ASCENDING, 0, average);
printf("average %g %g %g %g\n", average[0], average[1], average[2], average[3]);
const char* names[] = {"ordinal", "min", "max", "dense"};
for (int ties = 1; ties <= 4; ties++) {
uint64_t r[4];
kwker_i32_rank(points, 4, KWKER_ASCENDING, ties % 4, r);
printf("%-8s %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 "\n", names[ties % 4], r[0], r[1], r[2], r[3]);
}
return 0;
}
average 1 2.5 2.5 4 min 1 2 2 4 max 1 3 3 4 dense 1 2 2 3 ordinal 1 2 3 4
#include <iostream>
#include <vector>
#include <kwker.hpp>
int main() {
std::vector<int> points{10, 20, 20, 30};
std::cout << "average ";
for (double r : kwker::rank_average(points.data(), points.size())) std::cout << ' ' << r;
std::cout << '\n';
using T = kwker::Ties;
for (auto [name, ties] : {std::pair{"min ", T::min}, {"max ", T::max}, {"dense ", T::dense}, {"ordinal ", T::ordinal}}) {
std::cout << name;
for (auto r : kwker::rank(points, kwker::Order::ascending, ties)) std::cout << ' ' << r;
std::cout << '\n';
}
}
average 1 2.5 2.5 4 min 1 2 2 4 max 1 3 3 4 dense 1 2 2 3 ordinal 1 2 3 4
const kwk = require("kwker");
const points = new Int32Array([10, 20, 20, 30]);
for (const method of ["average", "min", "max", "dense", "ordinal"]) {
console.log(method.padEnd(8), kwk.rank(points, { method }));
}
average Float64Array(4) [ 1, 2.5, 2.5, 4 ]
min Float64Array(4) [ 1, 2, 2, 4 ]
max Float64Array(4) [ 1, 3, 3, 4 ]
dense Float64Array(4) [ 1, 2, 2, 3 ]
ordinal Float64Array(4) [ 1, 2, 3, 4 ]
package main
import (
"fmt"
"kwker.io/go/kwker"
)
func main() {
points := []int32{10, 20, 20, 30}
fmt.Println("average ", kwker.RankAverage(points, kwker.Ascending))
fmt.Println("min ", kwker.Rank(points, kwker.Ascending, kwker.Min))
fmt.Println("max ", kwker.Rank(points, kwker.Ascending, kwker.Max))
fmt.Println("dense ", kwker.Rank(points, kwker.Ascending, kwker.Dense))
fmt.Println("ordinal ", kwker.Rank(points, kwker.Ascending, kwker.Ordinal))
}
average [1 2.5 2.5 4] min [1 2 2 4] max [1 3 3 4] dense [1 2 2 3] ordinal [1 2 3 4]
import io.kwker.Kwker;
import java.util.Arrays;
public class Example {
public static void main(String[] args) {
int[] points = {10, 20, 20, 30};
System.out.println("average " + Arrays.toString(Kwker.rankAverage(points, Kwker.ASCENDING)));
System.out.println("min " + Arrays.toString(Kwker.rank(points, Kwker.TIES_MIN, Kwker.ASCENDING)));
System.out.println("max " + Arrays.toString(Kwker.rank(points, Kwker.TIES_MAX, Kwker.ASCENDING)));
System.out.println("dense " + Arrays.toString(Kwker.rank(points, Kwker.TIES_DENSE, Kwker.ASCENDING)));
System.out.println("ordinal " + Arrays.toString(Kwker.rank(points, Kwker.TIES_ORDINAL, Kwker.ASCENDING)));
}
}
average [1.0, 2.5, 2.5, 4.0] min [1, 2, 2, 4] max [1, 3, 3, 4] dense [1, 2, 2, 3] ordinal [1, 2, 3, 4]
using Kwker;
var points = new int[] { 10, 20, 20, 30 };
Console.WriteLine("average " + string.Join(" ", Sorter.RankAverage(points)));
Console.WriteLine("min " + string.Join(" ", Sorter.Rank(points, Ties.Min)));
Console.WriteLine("max " + string.Join(" ", Sorter.Rank(points, Ties.Max)));
Console.WriteLine("dense " + string.Join(" ", Sorter.Rank(points, Ties.Dense)));
Console.WriteLine("ordinal " + string.Join(" ", Sorter.Rank(points, Ties.Ordinal)));
average 1 2.5 2.5 4 min 1 2 2 4 max 1 3 3 4 dense 1 2 2 3 ordinal 1 2 3 4
percent_rank(a) returns where each value stands between 0 (the lowest) and 1 (the highest), as SQL's
PERCENT_RANK() does.
import numpy as np
import kwker
print(kwker.percent_rank(np.array([10, 20, 20, 30])))
[0. 0.33333333 0.33333333 1. ]
use kwker::Order;
fn main() {
println!("{:?}", kwker::percent_rank(&[10, 20, 20, 30], Order::ASCENDING));
}
[0.0, 0.3333333333333333, 0.3333333333333333, 1.0]
#include <stdio.h>
#include <kwker.h>
int main(void) {
const int32_t points[] = {10, 20, 20, 30};
double r[4];
kwker_i32_rank_f64(points, 4, KWKER_ASCENDING, 1, r); /* kind 1: percent rank */
printf("%g %g %g %g\n", r[0], r[1], r[2], r[3]);
return 0;
}
0 0.333333 0.333333 1
#include <iostream>
#include <vector>
#include <kwker.hpp>
int main() {
std::vector<int> points{10, 20, 20, 30};
for (double r : kwker::percent_rank(points.data(), points.size())) std::cout << r << ' ';
std::cout << '\n';
}
0 0.333333 0.333333 1
const kwk = require("kwker");
console.log(kwk.percentRank(new Int32Array([10, 20, 20, 30])));
Float64Array(4) [ 0, 0.3333333333333333, 0.3333333333333333, 1 ]
package main
import (
"fmt"
"kwker.io/go/kwker"
)
func main() {
fmt.Println(kwker.PercentRank([]int32{10, 20, 20, 30}, kwker.Ascending))
}
[0 0.3333333333333333 0.3333333333333333 1]
import io.kwker.Kwker;
import java.util.Arrays;
public class Example {
public static void main(String[] args) {
System.out.println(Arrays.toString(Kwker.percentRank(new int[] {10, 20, 20, 30}, Kwker.ASCENDING)));
}
}
[0.0, 0.3333333333333333, 0.3333333333333333, 1.0]
using Kwker;
Console.WriteLine(string.Join(" ", Sorter.PercentRank(new int[] { 10, 20, 20, 30 })));
0 0.3333333333333333 0.3333333333333333 1
Sort by several columns
lexsort(columns) orders rows by the first column, then by the second where the first is equal, and so on, like SQL
ORDER BY a, b. Each column can have its own direction.
import numpy as np
import kwker
team = np.array([2, 1, 2, 1, 2])
points = np.array([7, 9, 9, 4, 7])
order = kwker.lexsort([team, points], descending=[False, True]) # ORDER BY team, points DESC
print(order)
print(team[order], points[order])
[1 3 2 0 4]
[1 1 2 2 2] [9 4 9 7 7]
use kwker::{KeyColumn, Order};
fn main() {
let team = vec![2, 1, 2, 1, 2];
let points = vec![7, 9, 9, 4, 7];
// ORDER BY team, points DESC
let order = kwker::lexsort(&[(&team as &dyn KeyColumn, Order::ASCENDING), (&points as &dyn KeyColumn, Order::DESCENDING)]);
println!("{:?}", order.as_slice());
}
[1, 3, 2, 0, 4]
#include <inttypes.h>
#include <stdio.h>
#include <kwker.h>
int main(void) {
const int32_t team[] = {2, 1, 2, 1, 2};
const int32_t points[] = {7, 9, 9, 4, 7};
const kwker_column cols[] = {
{team, KWKER_TYPE_I32, KWKER_ASCENDING}, /* ORDER BY team, */
{points, KWKER_TYPE_I32, KWKER_DESCENDING}, /* points DESC */
};
uint64_t order[5];
kwker_lexsort(cols, 2, 5, order);
for (int i = 0; i < 5; i++) printf(i ? " %" PRIu64 : "%" PRIu64, order[i]);
printf("\n");
return 0;
}
1 3 2 0 4
#include <iostream>
#include <vector>
#include <kwker.hpp>
int main() {
std::vector<int> team{2, 1, 2, 1, 2};
std::vector<int> points{7, 9, 9, 4, 7};
// ORDER BY team, points DESC
auto order = kwker::lexsort({kwker::Column(team), kwker::Column(points, kwker::Order::descending)});
for (auto i : order) std::cout << i << ' ';
std::cout << '\n';
}
1 3 2 0 4
const kwk = require("kwker");
const team = new Int32Array([2, 1, 2, 1, 2]);
const points = new Int32Array([7, 9, 9, 4, 7]);
console.log(kwk.lexsort([team, points], { descending: [false, true] })); // ORDER BY team, points DESC
Uint32Array(5) [ 1, 3, 2, 0, 4 ]
package main
import (
"fmt"
"kwker.io/go/kwker"
)
func main() {
team := []int32{2, 1, 2, 1, 2}
points := []int32{7, 9, 9, 4, 7}
// ORDER BY team, points DESC
order := kwker.LexSort(kwker.Col(team, kwker.Ascending), kwker.Col(points, kwker.Descending))
fmt.Println(order)
for _, i := range order {
fmt.Print(team[i], ":", points[i], " ")
}
fmt.Println()
}
[1 3 2 0 4] 1:9 1:4 2:9 2:7 2:7
import io.kwker.Kwker;
import java.util.Arrays;
public class Example {
public static void main(String[] args) {
int[] team = {2, 1, 2, 1, 2};
int[] points = {7, 9, 9, 4, 7};
// ORDER BY team, points DESC
int[] order = Kwker.lexsort(Kwker.Column.of(team), Kwker.Column.of(points, Kwker.DESCENDING));
System.out.println(Arrays.toString(order));
StringBuilder rows = new StringBuilder();
for (int i : order) rows.append(team[i]).append(':').append(points[i]).append(' ');
System.out.println(rows.toString().trim());
}
}
[1, 3, 2, 0, 4] 1:9 1:4 2:9 2:7 2:7
using Kwker;
var team = new[] { 2, 1, 2, 1, 2 };
var points = new[] { 7, 9, 9, 4, 7 };
// ORDER BY team, points DESC
var order = Sorter.LexSort(Sorter.Column.Of(team), Sorter.Column.Of(points, Order.Descending));
Console.WriteLine(string.Join(" ", order));
Console.WriteLine(string.Join(" ", order.Select(i => $"{team[i]}:{points[i]}")));
1 3 2 0 4 1:9 1:4 2:9 2:7 2:7
The first column decides first. NumPy's numpy.lexsort takes the columns in the opposite order, with the last column
deciding first.
lex_top_k(columns, k) returns the first k rows of that order without ordering every row, like SQL ORDER BY ... LIMIT k.
import numpy as np
import kwker
team = np.array([2, 1, 2, 1, 2])
points = np.array([7, 9, 9, 4, 7])
print(kwker.lex_top_k([team, points], 2, descending=[False, True]))
[1 3]
use kwker::{KeyColumn, Order};
fn main() {
let team = vec![2, 1, 2, 1, 2];
let points = vec![7, 9, 9, 4, 7];
let first = kwker::lex_top_k(&[(&team as &dyn KeyColumn, Order::ASCENDING), (&points as &dyn KeyColumn, Order::DESCENDING)], 2);
println!("{first:?}");
}
[1, 3]
#include <inttypes.h>
#include <stdio.h>
#include <kwker.h>
int main(void) {
const int32_t team[] = {2, 1, 2, 1, 2};
const int32_t points[] = {7, 9, 9, 4, 7};
const kwker_column cols[] = {{team, KWKER_TYPE_I32, KWKER_ASCENDING},
{points, KWKER_TYPE_I32, KWKER_DESCENDING}};
uint64_t first[2];
kwker_lex_top_k(cols, 2, 5, 2, first);
printf("%" PRIu64 " %" PRIu64 "\n", first[0], first[1]);
return 0;
}
1 3
#include <iostream>
#include <vector>
#include <kwker.hpp>
int main() {
std::vector<int> team{2, 1, 2, 1, 2};
std::vector<int> points{7, 9, 9, 4, 7};
for (auto i : kwker::lex_top_k({kwker::Column(team), kwker::Column(points, kwker::Order::descending)}, 2))
std::cout << i << ' ';
std::cout << '\n';
}
1 3
const kwk = require("kwker");
const team = new Int32Array([2, 1, 2, 1, 2]);
const points = new Int32Array([7, 9, 9, 4, 7]);
console.log(kwk.lexTopK([team, points], 2, { descending: [false, true] }));
Uint32Array(2) [ 1, 3 ]
package main
import (
"fmt"
"kwker.io/go/kwker"
)
func main() {
team := []int32{2, 1, 2, 1, 2}
points := []int32{7, 9, 9, 4, 7}
fmt.Println(kwker.LexTopK(2, kwker.Col(team, kwker.Ascending), kwker.Col(points, kwker.Descending)))
}
[1 3]
import io.kwker.Kwker;
import java.util.Arrays;
public class Example {
public static void main(String[] args) {
int[] team = {2, 1, 2, 1, 2};
int[] points = {7, 9, 9, 4, 7};
System.out.println(Arrays.toString(Kwker.lexTopK(2, Kwker.Column.of(team), Kwker.Column.of(points, Kwker.DESCENDING))));
}
}
[1, 3]
using Kwker;
var team = new[] { 2, 1, 2, 1, 2 };
var points = new[] { 7, 9, 9, 4, 7 };
Console.WriteLine(string.Join(" ", Sorter.LexTopK(2, Sorter.Column.Of(team), Sorter.Column.Of(points, Order.Descending))));
1 3
Reorder records in place
permute_in_place(records, order) reorders an array of records (structs) by an order from argsort, without making
a copy of the array.
import numpy as np
import kwker
rows = np.array([(1, 3.5), (2, 1.0), (3, 2.25)], dtype=[("id", "i4"), ("score", "f8")])
kwker.permute_in_place(rows, kwker.argsort(rows["score"]))
print(rows["id"], rows["score"])
[2 3 1] [1. 2.25 3.5 ]
use kwker::Order;
#[derive(Debug)]
struct Row {
id: i32,
score: f64,
}
fn main() {
let mut rows = vec![Row { id: 1, score: 3.5 }, Row { id: 2, score: 1.0 }, Row { id: 3, score: 2.25 }];
let scores: Vec<f64> = rows.iter().map(|r| r.score).collect();
let order: Vec<u64> = kwker::argsort(&scores, Order::ASCENDING);
kwker::permute_in_place(&mut rows, &order);
println!("{rows:?}");
}
[Row { id: 2, score: 1.0 }, Row { id: 3, score: 2.25 }, Row { id: 1, score: 3.5 }]
#include <stdio.h>
#include <kwker.h>
typedef struct { int32_t id; double score; } row;
int main(void) {
row rows[] = {{1, 3.5}, {2, 1.0}, {3, 2.25}};
double score[3];
for (int i = 0; i < 3; i++) score[i] = rows[i].score;
uint64_t order[3];
kwker_f64_argsort(score, 3, KWKER_ASCENDING, order);
kwker_permute_in_place(rows, 3, sizeof(row), order);
for (int i = 0; i < 3; i++) printf("%d %g\n", rows[i].id, rows[i].score);
return 0;
}
2 1 3 2.25 1 3.5
#include <iostream>
#include <vector>
#include <kwker.hpp>
struct Row { int id; double score; };
int main() {
std::vector<Row> rows{{1, 3.5}, {2, 1.0}, {3, 2.25}};
std::vector<double> score;
for (const Row& r : rows) score.push_back(r.score);
kwker::permute_in_place(rows.data(), rows.size(), kwker::argsort(score));
for (const Row& r : rows) std::cout << r.id << ' ' << r.score << '\n';
}
2 1 3 2.25 1 3.5
package main
import (
"fmt"
"kwker.io/go/kwker"
)
type Row struct {
ID int32
Score float64
}
func main() {
rows := []Row{{1, 3.5}, {2, 1.0}, {3, 2.25}}
scores := make([]float64, len(rows))
for i, r := range rows {
scores[i] = r.Score
}
kwker.PermuteInPlace(rows, kwker.Argsort(scores, kwker.Ascending))
fmt.Println(rows)
}
[{2 1} {3 2.25} {1 3.5}]
import io.kwker.Kwker;
import java.util.Arrays;
public class Example {
record Row(int id, double score) {}
public static void main(String[] args) {
Row[] rows = {new Row(1, 3.5), new Row(2, 1.0), new Row(3, 2.25)};
double[] scores = Arrays.stream(rows).mapToDouble(Row::score).toArray();
Kwker.permuteInPlace(rows, Kwker.argsort(scores, Kwker.ASCENDING));
System.out.println(Arrays.toString(rows));
}
}
[Row[id=2, score=1.0], Row[id=3, score=2.25], Row[id=1, score=3.5]]
using Kwker;
var rows = new (int Id, double Score)[] { (1, 3.5), (2, 1.0), (3, 2.25) };
var order = Sorter.ArgSort(rows.Select(r => r.Score).ToArray());
Sorter.PermuteInPlace<(int, double)>(rows, order);
Console.WriteLine(string.Join(" ", rows));
(2, 1) (3, 2.25) (1, 3.5)
Related
- Sorting
- Top-k and selection
- DataFrames, Arrow and DuckDB: the same for pandas, Polars and pyarrow tables.
- API reference:
argsort,rank,lexsort