0

我刚开始编程,我正在用 Java 编写一个程序,用于使用 Single Transferable Vote 计算选票。我在一个 Excel 文件中有输入数据,如下所示:

这个

其中候选人的名字映射到a中它下面的数字,HashTable第2行下面的每一行从左到右代表一个选民的偏好。

我想添加名称和投票,TreeTableView看起来像这样:

这个.

每个候选者是他们第二个偏好的根,每个第二个偏好是第三个偏好的根,每个第三个偏好是第四个偏好的根,依此类推。

我正在使用该apache.poi库来使用 Excel 文件。我正在寻找有关如何表示工作表中的分层数据以及如何将其添加到TreeTabeView. 我怎么能这样做?

对不起,如果这是一个菜鸟问题。我对如何使用分层数据不是很熟悉。提前致谢!

4

1 回答 1

0

使用具有 2 个属性的项目类

  • 候选人
  • 票数

会做的伎俩(=每列一个属性)。例如

public class VoteEntry {

    // candidate INDEX
    private final IntegerProperty candidate;

    private final IntegerProperty voteCount;

    public VoteEntry(int candidate, int count) {
        this.voteCount = new SimpleIntegerProperty(count);
        this.candidate = new SimpleIntegerProperty(candidate);
    }

    public final int getCandidate() {
        return this.candidate.get();
    }

    public final void setCandidate(int value) {
        this.candidate.set(value);
    }

    public final IntegerProperty candidateProperty() {
        return this.candidate;
    }

    public final int getVoteCount() {
        return this.voteCount.get();
    }

    public final void setVoteCount(int value) {
        this.voteCount.set(value);
    }

    public final IntegerProperty voteCountProperty() {
        return this.voteCount;
    }

}

您可以将投票分组到越来越小的子组以创建TreeItem层次结构:

private final List<int[]> votes = new ArrayList<>();

private void addVote(int... preferences) {
    // convert to array of candidate indices sorted descendingly by preference
    int[] votes = new int[preferences.length];
    for (int i = 0; i < preferences.length; i++) {
        votes[preferences[i] - 1] = i;
    }
    this.votes.add(votes);
}

private static void createHierarchy(TreeItem<VoteEntry> parent, List<int[]> votes, int index) {
    int max = votes.stream().mapToInt(a -> a.length).max().getAsInt();
    if (max > index) {
        // group by candidate
        Map<Integer, List<int[]>> groups = votes.stream().collect(Collectors.groupingBy(a -> a.length > index ? a[index] : -1));
        groups.forEach((candidate, vts) -> {
            if (candidate != -1) {
                VoteEntry entry = new VoteEntry(candidate, vts.size());
                TreeItem<VoteEntry> item = new TreeItem<>(entry);
                parent.getChildren().add(item);
                createHierarchy(item, vts, index + 1);
            }
        });

        // sort by candidate
        parent.getChildren().sort(Comparator.comparingInt(ti -> ti.getValue().getCandidate()));
    }
}

@Override
public void start(Stage primaryStage) {
    addVote(1, 2, 3, 4);
    addVote(4, 3, 2, 1);
    addVote(1, 3, 2, 4);
    addVote(2, 1, 4, 3);
    addVote(2, 4, 3, 1);
    addVote(2, 1, 3, 4);
    // ...

    ObservableList<String> candidateNames = FXCollections.observableArrayList(
            "Candidate 1",
            "Candidate 2",
            "Candidate 3",
            "Candidate 4"
            );

    TreeItem<VoteEntry> root = new TreeItem<>();
    createHierarchy(root, votes, 0);

    TreeTableView<VoteEntry> view = new TreeTableView<>(root);
    view.setShowRoot(false);

    TreeTableColumn<VoteEntry, String> candidateColumn = new TreeTableColumn<>("candidate");
    candidateColumn.setCellValueFactory(data -> Bindings.valueAt(candidateNames, data.getValue().getValue().candidateProperty()));

    TreeTableColumn<VoteEntry, Integer> votesColumn = new TreeTableColumn<>("votes");
    votesColumn.setCellValueFactory(new TreeItemPropertyValueFactory<>("voteCount"));

    view.getColumns().addAll(candidateColumn, votesColumn);

    Scene scene = new Scene(view);

    primaryStage.setScene(scene);
    primaryStage.show();
}

请注意,递归方法仅适用于有限数量的候选者(stackoverflows)。但它应该适用于合理的候选数量(用户不想扩展数百个项目......)。

于 2016-05-16T18:39:03.117 回答