Quickstart: Kwker Core
Kwker Core is the engine under every other workflow: it sorts, selects and ranks arrays, in Python and 19 more languages. Install Kwker, then sort an array, find its top values, get its order and its median. About five minutes.
Each example has a tab per language; Default code language in the menu picks yours for the whole site. Python and JavaScript examples run here in your browser (a WebAssembly build: slower than native, same results).
Install
pip install kwker
cargo add kwker
# unpack the release archive for your platform (see Installation), then:
cc main.c $(pkg-config --cflags --libs kwker) -o main
# unpack the release archive for your platform (see Installation), then:
c++ -std=c++17 main.cpp $(pkg-config --cflags --libs kwker) -o main
npm install kwker
# install the C package for your platform first (see Installation), then:
go get kwker.io/go/kwker
# kwker.jar carries the native library for your platform
javac -cp kwker.jar Example.java
java -cp kwker.jar:. Example
dotnet add package Kwker
Python needs 3.9 or newer and NumPy. For other languages and platforms, see Installation.
Sort an array
sort sorts an array in place: the array itself changes.
import numpy as np
import kwker
prices = np.array([19.99, 4.5, 120.0, 0.99, 35.0])
kwker.sort(prices)
print(prices)
[ 0.99 4.5 19.99 35. 120. ]
fn main() {
let mut prices = [19.99, 4.5, 120.0, 0.99, 35.0];
kwker::sort(&mut prices);
println!("{prices:?}");
}
[0.99, 4.5, 19.99, 35.0, 120.0]
#include <stdio.h>
#include <kwker.h>
int main(void) {
double prices[] = {19.99, 4.5, 120.0, 0.99, 35.0};
kwker_f64_sort(prices, 5);
for (int i = 0; i < 5; i++) printf(i ? " %g" : "%g", prices[i]);
printf("\n");
return 0;
}
0.99 4.5 19.99 35 120
#include <iostream>
#include <vector>
#include <kwker.hpp>
int main() {
std::vector<double> prices{19.99, 4.5, 120.0, 0.99, 35.0};
kwker::sort(prices);
for (double p : prices) std::cout << p << ' ';
std::cout << '\n';
}
0.99 4.5 19.99 35 120
const kwk = require("kwker");
const prices = new Float64Array([19.99, 4.5, 120.0, 0.99, 35.0]);
kwk.sort(prices);
console.log(prices);
Float64Array(5) [ 0.99, 4.5, 19.99, 35, 120 ]
package main
import (
"fmt"
"kwker.io/go/kwker"
)
func main() {
prices := []float64{19.99, 4.5, 120.0, 0.99, 35.0}
kwker.Sort(prices)
fmt.Println(prices)
}
[0.99 4.5 19.99 35 120]
import io.kwker.Kwker;
import java.util.Arrays;
public class Example {
public static void main(String[] args) {
double[] prices = {19.99, 4.5, 120.0, 0.99, 35.0};
Kwker.sort(prices);
System.out.println(Arrays.toString(prices));
}
}
[0.99, 4.5, 19.99, 35.0, 120.0]
using Kwker;
var prices = new double[] { 19.99, 4.5, 120.0, 0.99, 35.0 };
Sorter.Sort(prices);
Console.WriteLine(string.Join(" ", prices));
0.99 4.5 19.99 35 120
Every integer and float type works the same way.
Largest first, or a sorted copy
Ask for a descending order to get the largest first. Sort a copy when you need to keep the original as it is
(kwker.sorted in Python).
import numpy as np
import kwker
scores = np.array([72, 95, 88, 61, 95], dtype=np.int32)
print(kwker.sorted(scores, descending=True))
print(scores) # unchanged
[95 95 88 72 61]
[72 95 88 61 95]
fn main() {
let scores = [72, 95, 88, 61, 95];
let mut best = scores;
kwker::sort_descending(&mut best);
println!("{best:?}");
println!("{scores:?}"); // unchanged
}
[95, 95, 88, 72, 61] [72, 95, 88, 61, 95]
#include <stdio.h>
#include <string.h>
#include <kwker.h>
int main(void) {
const int32_t scores[] = {72, 95, 88, 61, 95};
int32_t best[5];
memcpy(best, scores, sizeof scores);
kwker_i32_sort_order(best, 5, KWKER_DESCENDING);
for (int i = 0; i < 5; i++) printf(i ? " %d" : "%d", best[i]);
printf("\n");
for (int i = 0; i < 5; i++) printf(i ? " %d" : "%d", scores[i]); /* unchanged */
printf("\n");
return 0;
}
95 95 88 72 61 72 95 88 61 95
#include <iostream>
#include <vector>
#include <kwker.hpp>
int main() {
const std::vector<int> scores{72, 95, 88, 61, 95};
std::vector<int> best = scores;
kwker::sort(best, kwker::Order::descending);
for (int s : best) std::cout << s << ' ';
std::cout << '\n';
for (int s : scores) std::cout << s << ' '; // unchanged
std::cout << '\n';
}
95 95 88 72 61 72 95 88 61 95
const kwk = require("kwker");
const scores = new Int32Array([72, 95, 88, 61, 95]);
console.log(kwk.sort(scores.slice(), { descending: true }));
console.log(scores); // unchanged
Int32Array(5) [ 95, 95, 88, 72, 61 ]
Int32Array(5) [ 72, 95, 88, 61, 95 ]
package main
import (
"fmt"
"slices"
"kwker.io/go/kwker"
)
func main() {
scores := []int32{72, 95, 88, 61, 95}
best := slices.Clone(scores)
kwker.SortOrder(best, kwker.Descending)
fmt.Println(best)
fmt.Println(scores) // unchanged
}
[95 95 88 72 61] [72 95 88 61 95]
import io.kwker.Kwker;
import java.util.Arrays;
public class Example {
public static void main(String[] args) {
int[] scores = {72, 95, 88, 61, 95};
int[] best = scores.clone();
Kwker.sort(best, Kwker.DESCENDING);
System.out.println(Arrays.toString(best));
System.out.println(Arrays.toString(scores)); // unchanged
}
}
[95, 95, 88, 72, 61] [72, 95, 88, 61, 95]
using Kwker;
var scores = new int[] { 72, 95, 88, 61, 95 };
var best = (int[])scores.Clone();
Sorter.Sort(best, Order.Descending);
Console.WriteLine(string.Join(" ", best));
Console.WriteLine(string.Join(" ", scores)); // unchanged
95 95 88 72 61 72 95 88 61 95
Find the top results
top_k returns the k largest (or smallest) values and their positions, without sorting the whole array.
import numpy as np
import kwker
latency_ms = np.array([12.1, 250.4, 8.9, 97.0, 310.2, 15.5, 260.0])
values, positions = kwker.top_k(latency_ms, 3, descending=True)
print(values)
print(positions)
[310.2 260. 250.4]
[4 6 1]
use kwker::Order;
fn main() {
let latency_ms = [12.1, 250.4, 8.9, 97.0, 310.2, 15.5, 260.0];
let (values, positions): (Vec<f64>, Vec<usize>) = kwker::top_k(&latency_ms, 3, Order::DESCENDING, true);
println!("{values:?}");
println!("{positions:?}");
}
[310.2, 260.0, 250.4] [4, 6, 1]
#include <inttypes.h>
#include <stdio.h>
#include <kwker.h>
int main(void) {
const double latency_ms[] = {12.1, 250.4, 8.9, 97.0, 310.2, 15.5, 260.0};
double values[3];
uint64_t positions[3];
kwker_f64_top_k(latency_ms, 7, 3, KWKER_DESCENDING, 1, values, positions);
for (int i = 0; i < 3; i++) printf("%g at %" PRIu64 "\n", values[i], positions[i]);
return 0;
}
310.2 at 4 260 at 6 250.4 at 1
#include <iostream>
#include <vector>
#include <kwker.hpp>
int main() {
std::vector<double> latency_ms{12.1, 250.4, 8.9, 97.0, 310.2, 15.5, 260.0};
auto [values, positions] = kwker::top_k(latency_ms, 3, kwker::Order::descending);
for (size_t i = 0; i < values.size(); i++) std::cout << values[i] << " at " << positions[i] << '\n';
}
310.2 at 4 260 at 6 250.4 at 1
const kwk = require("kwker");
const latencyMs = new Float64Array([12.1, 250.4, 8.9, 97.0, 310.2, 15.5, 260.0]);
const { values, indices } = kwk.topK(latencyMs, 3, { descending: true });
console.log(values);
console.log(indices);
Float64Array(3) [ 310.2, 260, 250.4 ]
Uint32Array(3) [ 4, 6, 1 ]
package main
import (
"fmt"
"kwker.io/go/kwker"
)
func main() {
latencyMs := []float64{12.1, 250.4, 8.9, 97.0, 310.2, 15.5, 260.0}
values, positions := kwker.TopK(latencyMs, 3, kwker.Descending, true)
fmt.Println(values)
fmt.Println(positions)
}
[310.2 260 250.4] [4 6 1]
import io.kwker.Kwker;
public class Example {
public static void main(String[] args) {
double[] latencyMs = {12.1, 250.4, 8.9, 97.0, 310.2, 15.5, 260.0};
int[] positions = Kwker.topK(latencyMs, 3, Kwker.DESCENDING);
for (int i : positions) System.out.println(latencyMs[i] + " at " + i);
}
}
310.2 at 4 260.0 at 6 250.4 at 1
using Kwker;
var latencyMs = new double[] { 12.1, 250.4, 8.9, 97.0, 310.2, 15.5, 260.0 };
var (values, positions) = Sorter.TopK<double>(latencyMs, 3, Order.Descending);
for (int i = 0; i < values.Length; i++) Console.WriteLine($"{values[i]} at {positions[i]}");
310.2 at 4 260 at 6 250.4 at 1
Get the order, not the sorted data
argsort returns the positions that would sort the array. Use them to put other data in the same order.
import numpy as np
import kwker
names = np.array(["Ana", "Ben", "Chen", "Dara", "Eli"])
age = np.array([34, 27, 41, 27, 30], dtype=np.uint8)
order = kwker.argsort(age)
print(order)
print(names[order])
[1 3 4 0 2]
['Ben' 'Dara' 'Eli' 'Ana' 'Chen']
use kwker::Order;
fn main() {
let names = ["Ana", "Ben", "Chen", "Dara", "Eli"];
let age: [u8; 5] = [34, 27, 41, 27, 30];
let order: Vec<usize> = kwker::argsort(&age, Order::ASCENDING);
println!("{order:?}");
let sorted: Vec<&str> = order.iter().map(|&i| names[i]).collect();
println!("{sorted:?}");
}
[1, 3, 4, 0, 2] ["Ben", "Dara", "Eli", "Ana", "Chen"]
#include <inttypes.h>
#include <stdio.h>
#include <kwker.h>
int main(void) {
const char* names[] = {"Ana", "Ben", "Chen", "Dara", "Eli"};
const uint8_t age[] = {34, 27, 41, 27, 30};
uint64_t order[5];
kwker_u8_argsort(age, 5, KWKER_ASCENDING, order);
for (int i = 0; i < 5; i++) printf(i ? " %" PRIu64 : "%" PRIu64, order[i]);
printf("\n");
for (int i = 0; i < 5; i++) printf(i ? " %s" : "%s", names[order[i]]);
printf("\n");
return 0;
}
1 3 4 0 2 Ben Dara Eli Ana Chen
#include <cstdint>
#include <iostream>
#include <string>
#include <vector>
#include <kwker.hpp>
int main() {
std::vector<std::string> names{"Ana", "Ben", "Chen", "Dara", "Eli"};
std::vector<uint8_t> age{34, 27, 41, 27, 30};
auto order = kwker::argsort(age);
for (auto i : order) std::cout << i << ' ';
std::cout << '\n';
for (auto i : order) std::cout << names[i] << ' ';
std::cout << '\n';
}
1 3 4 0 2 Ben Dara Eli Ana Chen
const kwk = require("kwker");
const names = ["Ana", "Ben", "Chen", "Dara", "Eli"];
const age = new Uint8Array([34, 27, 41, 27, 30]);
const order = kwk.argsort(age);
console.log(order);
console.log(Array.from(order, (i) => names[i]));
Uint32Array(5) [ 1, 3, 4, 0, 2 ]
[ 'Ben', 'Dara', 'Eli', 'Ana', 'Chen' ]
package main
import (
"fmt"
"kwker.io/go/kwker"
)
func main() {
names := []string{"Ana", "Ben", "Chen", "Dara", "Eli"}
age := []uint8{34, 27, 41, 27, 30}
order := kwker.Argsort(age, kwker.Ascending)
fmt.Println(order)
sorted := make([]string, len(order))
for i, j := range order {
sorted[i] = names[j]
}
fmt.Println(sorted)
}
[1 3 4 0 2] [Ben Dara Eli Ana Chen]
import io.kwker.Kwker;
import java.util.Arrays;
public class Example {
public static void main(String[] args) {
String[] names = {"Ana", "Ben", "Chen", "Dara", "Eli"};
int[] age = {34, 27, 41, 27, 30};
int[] order = Kwker.argsort(age, Kwker.ASCENDING);
System.out.println(Arrays.toString(order));
String[] sorted = new String[order.length];
for (int i = 0; i < order.length; i++) sorted[i] = names[order[i]];
System.out.println(Arrays.toString(sorted));
}
}
[1, 3, 4, 0, 2] [Ben, Dara, Eli, Ana, Chen]
using Kwker;
var names = new[] { "Ana", "Ben", "Chen", "Dara", "Eli" };
var age = new int[] { 34, 27, 41, 27, 30 };
var order = Sorter.ArgSort<int>(age);
Console.WriteLine(string.Join(" ", order));
Console.WriteLine(string.Join(" ", order.Select(i => names[i])));
1 3 4 0 2 Ben Dara Eli Ana Chen
The median, without a full sort
select(a, k) puts the value a full sort would put at index k into a[k], without sorting the rest. That is all a
median or a percentile needs: for the median, k = n // 2.
import numpy as np
import kwker
a = np.array([7, 1, 9, 4, 3, 8, 2])
mid = len(a) // 2
kwker.select(a, mid)
print("median:", a[mid])
median: 4
fn main() {
let mut a = [7, 1, 9, 4, 3, 8, 2];
let mid = a.len() / 2;
kwker::select_nth(&mut a, mid);
println!("median: {}", a[mid]);
}
median: 4
#include <stdio.h>
#include <kwker.h>
int main(void) {
int32_t a[] = {7, 1, 9, 4, 3, 8, 2};
size_t mid = 7 / 2;
kwker_i32_select(a, 7, mid, KWKER_ASCENDING);
printf("median: %d\n", a[mid]);
return 0;
}
median: 4
#include <iostream>
#include <vector>
#include <kwker.hpp>
int main() {
std::vector<int> a{7, 1, 9, 4, 3, 8, 2};
size_t mid = a.size() / 2;
kwker::select(a, mid);
std::cout << "median: " << a[mid] << '\n';
}
median: 4
const kwk = require("kwker");
const a = new Int32Array([7, 1, 9, 4, 3, 8, 2]);
const mid = Math.floor(a.length / 2);
kwk.select(a, mid);
console.log("median:", a[mid]);
median: 4
package main
import (
"fmt"
"kwker.io/go/kwker"
)
func main() {
a := []int32{7, 1, 9, 4, 3, 8, 2}
mid := len(a) / 2
kwker.Select(a, mid, kwker.Ascending)
fmt.Println("median:", a[mid])
}
median: 4
import io.kwker.Kwker;
public class Example {
public static void main(String[] args) {
int[] a = {7, 1, 9, 4, 3, 8, 2};
int mid = a.length / 2;
Kwker.select(a, mid, Kwker.ASCENDING);
System.out.println("median: " + a[mid]);
}
}
median: 4
using Kwker;
var a = new int[] { 7, 1, 9, 4, 3, 8, 2 };
int mid = a.Length / 2;
Sorter.Select<int>(a, mid);
Console.WriteLine($"median: {a[mid]}");
median: 4
Check what runs on your machine
Kwker picks the fastest code for your CPU when it starts. isa() tells you which one runs.
import kwker
print(kwker.isa()) # for example: avx512
print(kwker.version())
From a terminal, python -m kwker doctor prints a full report, and python -m kwker bench --quick times Kwker against
the libraries installed on your machine.
Next steps
- Tutorials: lessons by workflow, from a leaderboard to a file larger than memory.
- Core concepts: in place or a copy, threads, sort order, memory and errors.
- How-to guides: sorting, top-k, ranks, searches, keys with values, strings, groups and large data.
- Playground: a full editor to try things in your browser.
- Languages: the same calls in Ruby, PHP, R, Swift and more.