Strings
Kwker sorts lists of strings and NumPy string arrays in one of four orders, called collations. The names each language uses are at the end of this page.
| Collation | Order | Example |
|---|---|---|
| bytes (default) | by the bytes of the text (code point order) | "B" < "a" < "b" |
| caseless | ignores the case of A-Z | "a" = "A" < "b" |
| natural | runs of digits compare as numbers | "file2" < "file10" |
| natural caseless | both of the above | "File2" < "file10" |
Sort a list of strings
sort_strings(strings, collation) sorts a list of strings (Python returns a new list). Strings that the collation
treats as equal keep their original order.
import kwker
files = ["file10.txt", "File2.txt", "file1.txt", "file2.txt"]
for collation in ["bytes", "caseless", "natural", "natural_caseless"]:
print(f"{collation:17}", kwker.sort_strings(files, collation))
bytes ['File2.txt', 'file1.txt', 'file10.txt', 'file2.txt']
caseless ['file1.txt', 'file10.txt', 'File2.txt', 'file2.txt']
natural ['File2.txt', 'file1.txt', 'file2.txt', 'file10.txt']
natural_caseless ['file1.txt', 'File2.txt', 'file2.txt', 'file10.txt']
use kwker::Collation;
fn main() {
let files = ["file10.txt", "File2.txt", "file1.txt", "file2.txt"];
for (name, c) in [("bytes", Collation::Bytes), ("caseless", Collation::AsciiCaseless),
("natural", Collation::Natural), ("natural_caseless", Collation::NaturalCaseless)] {
let mut v = files;
kwker::sort_strings(&mut v, c);
println!("{name:17} {v:?}");
}
}
bytes ["File2.txt", "file1.txt", "file10.txt", "file2.txt"] caseless ["file1.txt", "file10.txt", "File2.txt", "file2.txt"] natural ["File2.txt", "file1.txt", "file2.txt", "file10.txt"] natural_caseless ["file1.txt", "File2.txt", "file2.txt", "file10.txt"]
#include <stdio.h>
#include <string.h>
#include <kwker.h>
int main(void) {
const char* files[] = {"file10.txt", "File2.txt", "file1.txt", "file2.txt"};
size_t lens[4];
for (int i = 0; i < 4; i++) lens[i] = strlen(files[i]);
const char* names[] = {"bytes", "caseless", "natural", "natural_caseless"};
for (uint32_t c = KWKER_COLLATE_BYTES; c <= KWKER_COLLATE_NATURAL_CASELESS; c++) {
uint64_t order[4];
kwker_argsort_strings(files, lens, 4, c, order);
printf("%-17s", names[c]);
for (int i = 0; i < 4; i++) printf(" %s", files[order[i]]);
printf("\n");
}
return 0;
}
bytes File2.txt file1.txt file10.txt file2.txt caseless file1.txt file10.txt File2.txt file2.txt natural File2.txt file1.txt file2.txt file10.txt natural_caseless file1.txt File2.txt file2.txt file10.txt
#include <iostream>
#include <string>
#include <vector>
#include <kwker.hpp>
int main() {
const std::vector<std::string> files{"file10.txt", "File2.txt", "file1.txt", "file2.txt"};
using C = kwker::Collation;
for (auto [name, c] : {std::pair{"bytes ", C::bytes}, {"caseless ", C::ascii_caseless},
{"natural ", C::natural}, {"natural_caseless", C::natural_caseless}}) {
std::vector<std::string> v = files;
kwker::sort_strings(v, c);
std::cout << name;
for (const auto& s : v) std::cout << ' ' << s;
std::cout << '\n';
}
}
bytes File2.txt file1.txt file10.txt file2.txt caseless file1.txt file10.txt File2.txt file2.txt natural File2.txt file1.txt file2.txt file10.txt natural_caseless file1.txt File2.txt file2.txt file10.txt
const kwk = require("kwker");
const files = ["file10.txt", "File2.txt", "file1.txt", "file2.txt"];
for (const collation of ["bytes", "caseless", "natural", "natural_caseless"]) {
console.log(collation.padEnd(17), kwk.sortStrings(files.slice(), collation));
}
bytes [ 'File2.txt', 'file1.txt', 'file10.txt', 'file2.txt' ]
caseless [ 'file1.txt', 'file10.txt', 'File2.txt', 'file2.txt' ]
natural [ 'File2.txt', 'file1.txt', 'file2.txt', 'file10.txt' ]
natural_caseless [ 'file1.txt', 'File2.txt', 'file2.txt', 'file10.txt' ]
package main
import (
"fmt"
"kwker.io/go/kwker"
)
func main() {
files := []string{"file10.txt", "File2.txt", "file1.txt", "file2.txt"}
for _, c := range []struct {
name string
c kwker.Collation
}{{"bytes", kwker.CollateBytes}, {"caseless", kwker.CollateCaseless},
{"natural", kwker.CollateNatural}, {"natural_caseless", kwker.CollateNaturalCaseless}} {
s := append([]string(nil), files...)
kwker.SortStrings(s, c.c)
fmt.Printf("%-17s %q\n", c.name, s)
}
}
bytes ["File2.txt" "file1.txt" "file10.txt" "file2.txt"] caseless ["file1.txt" "file10.txt" "File2.txt" "file2.txt"] natural ["File2.txt" "file1.txt" "file2.txt" "file10.txt"] natural_caseless ["file1.txt" "File2.txt" "file2.txt" "file10.txt"]
import io.kwker.Kwker;
import java.util.Arrays;
public class Example {
public static void main(String[] args) {
String[] files = {"file10.txt", "File2.txt", "file1.txt", "file2.txt"};
String[] names = {"bytes", "caseless", "natural", "natural_caseless"};
int[] collations = {Kwker.COLLATE_BYTES, Kwker.COLLATE_CASELESS, Kwker.COLLATE_NATURAL, Kwker.COLLATE_NATURAL_CASELESS};
for (int c = 0; c < 4; c++) {
String[] s = files.clone();
Kwker.sortStrings(s, collations[c]);
System.out.printf("%-17s %s%n", names[c], Arrays.toString(s));
}
}
}
bytes [File2.txt, file1.txt, file10.txt, file2.txt] caseless [file1.txt, file10.txt, File2.txt, file2.txt] natural [File2.txt, file1.txt, file2.txt, file10.txt] natural_caseless [file1.txt, File2.txt, file2.txt, file10.txt]
using Kwker;
var files = new[] { "file10.txt", "File2.txt", "file1.txt", "file2.txt" };
foreach (var c in new[] { Sorter.Collation.Bytes, Sorter.Collation.Caseless,
Sorter.Collation.Natural, Sorter.Collation.NaturalCaseless })
{
var s = (string[])files.Clone();
Sorter.SortStrings(s, c);
Console.WriteLine($"{c,-17} {string.Join(", ", s)}");
}
Bytes File2.txt, file1.txt, file10.txt, file2.txt Caseless file1.txt, file10.txt, File2.txt, file2.txt Natural File2.txt, file1.txt, file2.txt, file10.txt NaturalCaseless file1.txt, File2.txt, file2.txt, file10.txt
The order of strings
argsort_strings(strings, collation) returns the positions that sort the strings. Use it to reorder other data by a
text column.
import numpy as np
import kwker
product = ["pear", "Apple", "fig", "banana"]
price = np.array([1.20, 0.80, 2.50, 0.30])
order = kwker.argsort_strings(product, "caseless")
print([product[i] for i in order])
print(price[order])
['Apple', 'banana', 'fig', 'pear']
[0.8 0.3 2.5 1.2]
use kwker::Collation;
fn main() {
let product = ["pear", "Apple", "fig", "banana"];
let price = [1.20, 0.80, 2.50, 0.30];
let order = kwker::argsort_strings(&product, Collation::AsciiCaseless);
for &i in order.as_slice() {
println!("{} {}", product[i], price[i]);
}
}
Apple 0.8 banana 0.3 fig 2.5 pear 1.2
#include <stdio.h>
#include <string.h>
#include <kwker.h>
int main(void) {
const char* product[] = {"pear", "Apple", "fig", "banana"};
const double price[] = {1.20, 0.80, 2.50, 0.30};
size_t lens[4];
for (int i = 0; i < 4; i++) lens[i] = strlen(product[i]);
uint64_t order[4];
kwker_argsort_strings(product, lens, 4, KWKER_COLLATE_ASCII_CASELESS, order);
for (int j = 0; j < 4; j++) printf("%s %g\n", product[order[j]], price[order[j]]);
return 0;
}
Apple 0.8 banana 0.3 fig 2.5 pear 1.2
#include <iostream>
#include <string>
#include <vector>
#include <kwker.hpp>
int main() {
std::vector<std::string> product{"pear", "Apple", "fig", "banana"};
std::vector<double> price{1.20, 0.80, 2.50, 0.30};
for (auto i : kwker::argsort_strings(product, kwker::Collation::ascii_caseless))
std::cout << product[i] << ' ' << price[i] << '\n';
}
Apple 0.8 banana 0.3 fig 2.5 pear 1.2
const kwk = require("kwker");
const product = ["pear", "Apple", "fig", "banana"];
const price = [1.20, 0.80, 2.50, 0.30];
for (const i of kwk.argsortStrings(product, "caseless")) console.log(product[i], price[i]);
Apple 0.8
banana 0.3
fig 2.5
pear 1.2
package main
import (
"fmt"
"kwker.io/go/kwker"
)
func main() {
product := []string{"pear", "Apple", "fig", "banana"}
price := []float64{1.20, 0.80, 2.50, 0.30}
for _, i := range kwker.ArgsortStrings(product, kwker.CollateCaseless) {
fmt.Println(product[i], price[i])
}
}
Apple 0.8 banana 0.3 fig 2.5 pear 1.2
import io.kwker.Kwker;
public class Example {
public static void main(String[] args) {
String[] product = {"pear", "Apple", "fig", "banana"};
double[] price = {1.20, 0.80, 2.50, 0.30};
for (int i : Kwker.argsortStrings(product, Kwker.COLLATE_CASELESS)) {
System.out.println(product[i] + " " + price[i]);
}
}
}
Apple 0.8 banana 0.3 fig 2.5 pear 1.2
using Kwker;
var product = new[] { "pear", "Apple", "fig", "banana" };
var price = new[] { 1.20, 0.80, 2.50, 0.30 };
foreach (int i in Sorter.ArgsortStrings(product, Sorter.Collation.Caseless))
Console.WriteLine($"{product[i]} {price[i]}");
Apple 0.8 banana 0.3 fig 2.5 pear 1.2
NumPy string arrays
In Python, arrays of type S (bytes) and U (text) work directly, and the result is an array.
import numpy as np
import kwker
codes = np.array(["B12", "A7", "B2", "A10"])
print(kwker.sort_strings(codes, "natural"))
['A7' 'A10' 'B2' 'B12']
Other alphabets and mainframe data
In the native packages, a collation can also be any table of 256 byte weights: kwker.collation_table("ebcdic037")
in Python, TABLE_EBCDIC_037 with sort_strings_table in Rust and kwker_argsort_strings_table in C order text
the way IBM mainframes do. Language-specific orders (German, Swedish, ...) are not built in: sort by keys made with a
library such as ICU.
Collation names in each language
| Language | bytes | caseless | natural | natural caseless |
|---|---|---|---|---|
| Python, JavaScript | "bytes" |
"caseless" |
"natural" |
"natural_ |
| Rust | Collation::Bytes |
AsciiCaseless |
Natural |
NaturalCaseless |
| C | KWKER_ |
KWKER_ |
KWKER_ |
KWKER_ |
| C++ | kwker::Collation::bytes |
ascii_ |
natural |
natural_ |
| Go | kwker.CollateBytes |
CollateCaseless |
CollateNatural |
CollateNaturalCaseless |
| Java | Kwker.COLLATE_ |
COLLATE_ |
COLLATE_ |
COLLATE_ |
| C# | Sorter.Collation.Bytes |
Caseless |
Natural |
NaturalCaseless |