Skip to content

Instantly share code, notes, and snippets.

@gigamonkey
Last active October 31, 2024 20:35
Show Gist options
  • Save gigamonkey/f552efa33a7a7383cb63282ebdf933d4 to your computer and use it in GitHub Desktop.
Save gigamonkey/f552efa33a7a7383cb63282ebdf933d4 to your computer and use it in GitHub Desktop.
Reviewer assignment algorithm. I'm not sure this actually can generate all possible legal combinations of assignments but it's pretty random and only generates legal assignments. I'm also not sure it can't. First version is mostly procedural. Second one is heavy on streams.
import static java.util.stream.Collectors.joining;
import java.io.*;
import java.nio.file.*;
import java.util.*;
import java.util.stream.*;
public record Reviewers(List<String> handles) {
//////////////////////////////////////////////////////////////////////////////
// Utility methods
// Return a randomly shuffled copy of a list
private <T> List<T> shuffled(List<T> ts) {
List<T> copy = new ArrayList<>(ts);
Collections.shuffle(copy);
return copy;
}
// Return a list of integers in the range [start, end)
private List<Integer> numbers(int start, int end) {
return IntStream.range(start, end).boxed().toList();
}
//////////////////////////////////////////////////////////////////////////////
// Actual reviewer assignment
public Map<String, List<String>> assignments(int n) {
var shuffled = shuffled(handles);
var rotations = shuffled(numbers(1, shuffled.size())).subList(0, n);
var assignments = new HashMap<String, List<String>>();
for (var i = 0; i < shuffled.size(); i++) {
for (var r : rotations) {
assignments
.computeIfAbsent(shuffled.get(i), k -> new ArrayList<>())
.add(shuffled.get((i + r) % shuffled.size()));
}
}
return assignments;
}
//////////////////////////////////////////////////////////////////////////////
// Output
public void tsv(int n) {
var m = assignments(n);
for (var h : handles) {
System.out.println(h + "\t" + m.get(h).stream().collect(joining("\t")));
}
}
public static void main(String[] args) throws IOException {
var handles = Files.lines(Path.of(args[0])).toList();
var n = Integer.parseInt(args[1]);
new Reviewers(handles).tsv(n);
}
}
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.mapping;
import static java.util.stream.Collectors.toList;
import java.io.*;
import java.nio.file.*;
import java.util.*;
import java.util.stream.*;
public record Reviewers2(List<String> handles) {
//////////////////////////////////////////////////////////////////////////////
// Utility methods
// Return a randomly shuffled copy of a list
private <T> List<T> shuffled(List<T> ts) {
List<T> copy = new ArrayList<>(ts);
Collections.shuffle(copy);
return copy;
}
// Return a list of integers in the range [start, end)
private List<Integer> numbers(int start, int end) {
return IntStream.range(start, end).boxed().toList();
}
//////////////////////////////////////////////////////////////////////////////
// Actual reviewer assignment
public Map<String, List<String>> assignments(int n) {
var hs = shuffled(handles);
var rs = shuffled(numbers(1, hs.size())).subList(0, n);
record Pair(String author, String reviewer) {}
return numbers(0, hs.size())
.stream()
.flatMap(i -> rs.stream().map(r -> new Pair(hs.get(i), hs.get((i + r) % hs.size()))))
.collect(groupingBy(Pair::author, mapping(Pair::reviewer, toList())));
}
//////////////////////////////////////////////////////////////////////////////
// Output
public void tsv(int n) {
var m = assignments(n);
for (var h : handles) {
System.out.println(h + "\t" + m.get(h).stream().collect(joining("\t")));
}
}
public static void main(String[] args) throws IOException {
var handles = Files.lines(Path.of(args[0])).toList();
var n = Integer.parseInt(args[1]);
new Reviewers(handles).tsv(n);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment