gpt4 book ai didi

java - 从另一个 ObservableList 中将映射的不同值派生到一个 ObservableList 中?

转载 作者:行者123 更新时间:2023-11-30 08:53:48 26 4
gpt4 key购买 nike

我有一个有趣的问题,我是 JavaFX 的新手,我需要创建一个小众市场 ObservableList执行。

本质上,我需要一个 ObservableList维护另一个 ObservableList 的映射派生值列表.我需要创建一个 ObservableDistinctList<P,V>接受另一个 ObservableList<P>和一个 Function<P,V> lambda 作为其构造函数参数。 ObservableDistinctList<P,V>维护应用 Function<P,V> 的不同值列表对于 ObservableList<P> 中的每个元素.

例如,假设我有 ObservableList<Flight> flights具有以下实例。

Flt #   Carrier Orig    Dest    Dep Date
174 WN ABQ DAL 5/6/2015
4673 WN DAL HOU 5/6/2015
485 DL DAL PHX 5/7/2015
6758 UA JFK HOU 5/7/2015

如果我根据每个 Flight 对象的承运人值创建一个新的 ObservableDistinctList,我将在客户端执行此操作。

ObservableDistinctList<Flight,String> distinctCarriers = new 
ObservableDistinctList(flights, f -> f.getCarrier());

这些将是 distinctCarriers 中唯一的值列表。

WN
DL
UA

如果将航类添加到 flights ,它会首先检查一个新的不同值是否确实存在,然后再添加它。所以一个新的 WN飞行不会导致增加 distinctCarriers列表,而是一个 AA飞行会。相反,如果航类从 flights 中删除,它需要检查其他实例是否会在删除之前保留该值。从 flights 中删除 WN 航类不会导致删除 WN来自 distinctCarriers列表,但删除了 DL飞行将导致其移除。

这是我的实现。我是否实现了 ListChangeListener正确吗?我对 List 可变性感到非常不舒服,所以我想在考虑在我的项目中使用它之前发布它。另外,我是否需要担心使用 ArrayList 的线程安全?支持这个?

public final class ObservableDistinctList<P,V> extends ObservableListBase<V> {

private final ObservableList<P> parentList;
private final Function<P,V> valueExtractor;
private final List<V> values;

public ObservableDistinctList(ObservableList<P> parentList, Function<P,V> valueExtractor) {
this.parentList = parentList;
this.valueExtractor = valueExtractor;
this.values = parentList.stream().map(p -> valueExtractor.apply(p)).distinct().collect(Collectors.toList());

this.parentList.addListener((ListChangeListener.Change<? extends P> c) -> {
while (c.next()) {
if (c.wasRemoved()) {
final Stream<V> candidatesForRemoval = c.getRemoved().stream().map(p -> valueExtractor.apply(p));
final List<V> persistingValues = parentList.stream().map(p -> valueExtractor.apply(p)).distinct().collect(Collectors.toList());

final Stream<V> valuesToRemove = candidatesForRemoval.filter(v -> ! persistingValues.contains(v));

valuesToRemove.forEach(v -> values.remove(v));
}

if (c.wasAdded()) {
final Stream<V> candidatesForAdd = c.getAddedSubList().stream().map(p -> valueExtractor.apply(p));
final List<V> existingValues = parentList.stream().map(p -> valueExtractor.apply(p)).distinct().collect(Collectors.toList());

final Stream<V> valuesToAdd = candidatesForAdd.filter(v -> ! values.contains(v));

valuesToAdd.forEach(v -> values.add(v));
}
}
});
}
@Override
public V get(int index) {
return values.get(index);
}

@Override
public int size() {
return values.size();
}
}

最佳答案

下面是一个简单示例(加上驱动程序 - 提示:这就是您应该在问题中提供的内容:-) 自定义 ObservableList,它在源列表中保留元素属性的不同值。它使自己在添加/删除项目时与源同步。同步由以下人员实现:

  • 监听源列表变化
  • 当收到一个被删除的消息时:如果被删除的是最后一个具有独特属性的,则从自己身上删除该属性并通知其自己的听众有关删除的信息。否则,无事可做。
  • 收到添加时:如果添加的是第一个具有不同属性的,则将属性添加到自己(最后)并通知其自己的监听器有关添加的信息。否则,无事可做。

通知是通过向实用程序方法 nextRemove/nextAdd 发送消息来处理的。

/**
* Example of how to implement a custom ObservableList.
*
* Here: an immutable and unmodifiable (in itself) list containing distinct
* values of properties of elements in a backing list, the values are extracted
* via a function
*/
public class DistinctMapperDemo extends Application {

public static class DistinctMappingList<V, E> extends ObservableListBase<E> {

private List<E> mapped;
private Function<V, E> mapper;

public DistinctMappingList(ObservableList<V> source, Function<V, E> mapper) {
this.mapper = mapper;
mapped = applyMapper(source);
ListChangeListener l = c -> sourceChanged(c);
source.addListener(l);
}

private void sourceChanged(Change<? extends V> c) {
beginChange();
List<E> backing = applyMapper(c.getList());
while(c.next()) {
if (c.wasAdded()) {
wasAdded(c, backing);
} else if (c.wasRemoved()) {
wasRemoved(c, backing);
} else {
// throw just for the example
throw new IllegalStateException("unexpected change " + c);
}
}
endChange();
}

private void wasRemoved(Change<? extends V> c, List<E> backing) {
List<E> removedCategories = applyMapper(c.getRemoved());
for (E e : removedCategories) {
if (!backing.contains(e)) {
int index = indexOf(e);
mapped.remove(index);
nextRemove(index, e);
}
}
}

private void wasAdded(Change<? extends V> c, List<E> backing) {
List<E> addedCategories = applyMapper(c.getAddedSubList());
for (E e : addedCategories) {
if (!contains(e)) {
int last = size();
mapped.add(e);
nextAdd(last, last +1);
}
}
}

private List<E> applyMapper(List<? extends V> list) {
List<E> backing = list.stream().map(p -> mapper.apply(p)).distinct()
.collect(Collectors.toList());
return backing;
}

@Override
public E get(int index) {
return mapped.get(index);
}

@Override
public int size() {
return mapped.size();
}

}

int categoryCount;
private Parent getContent() {
ObservableList<DemoData> data = FXCollections.observableArrayList(
new DemoData("first", "some"),
new DemoData("second", "some"),
new DemoData("first", "other"),
new DemoData("dup", "other"),
new DemoData("dodo", "next"),
new DemoData("getting", "last")

);
TableView<DemoData> table = new TableView<>(data);
TableColumn<DemoData, String> name = new TableColumn<>("Name");
name.setCellValueFactory(new PropertyValueFactory<>("name"));
TableColumn<DemoData, String> cat = new TableColumn<>("Category");
cat.setCellValueFactory(new PropertyValueFactory<>("category"));
table.getColumns().addAll(name, cat);

Function<DemoData, String> mapper = c -> c.categoryProperty().get();
ObservableList<String> mapped = new DistinctMappingList<>(data, mapper);
ListView<String> cats = new ListView<>(mapped);

Button remove = new Button("RemoveSelected DemoData");
remove.setOnAction(e -> {
int selected = table.getSelectionModel().getSelectedIndex();
if (selected <0) return;
data.remove(selected);
});

Button createNewCategory = new Button("Create DemoData with new Category");
createNewCategory.setOnAction(e -> {
String newCategory = data.size() == 0 ? "some" + categoryCount :
data.get(0).categoryProperty().get() + categoryCount;
data.add(new DemoData("name" + categoryCount, newCategory));
categoryCount++;
});
VBox buttons = new VBox(remove, createNewCategory);
HBox box = new HBox(table, cats, buttons);
return box;
}

public static class DemoData {
StringProperty name = new SimpleStringProperty(this, "name");
StringProperty category = new SimpleStringProperty(this, "category");

public DemoData(String name, String category) {
this.name.set(name);
this.category.set(category);
}

public StringProperty nameProperty() {
return name;
}

public StringProperty categoryProperty() {
return category;
}
}
@Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setScene(new Scene(getContent()));
primaryStage.show();
}

public static void main(String[] args) {
launch(args);
}

}

关于java - 从另一个 ObservableList 中将映射的不同值派生到一个 ObservableList 中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29656772/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com