Java 如何通过操纵可观察列表来引发置换事件?
侦听器可以接收具有排列集的事件 同时,在列表操作中,我只看到要删除或插入元素的操作 是否可以对列表执行这样的操作,这将导致报告置换 更新 以下是澄清代码:Java 如何通过操纵可观察列表来引发置换事件?,java,javafx,observablelist,Java,Javafx,Observablelist,侦听器可以接收具有排列集的事件 同时,在列表操作中,我只看到要删除或插入元素的操作 是否可以对列表执行这样的操作,这将导致报告置换 更新 以下是澄清代码: public class ObservableListPermutation { public static void main(String[] args) { ObservableList<String> list = FXCollections.observableArrayList();
public class ObservableListPermutation {
public static void main(String[] args) {
ObservableList<String> list = FXCollections.observableArrayList();
list.add("timbuktu");
list.add("timid");
list.addListener(new ListChangeListener<String>() {
@Override
public void onChanged(Change<? extends String> c) {
while(c.next()) {
if( c.wasPermutated() ) {
System.out.println("Was permutated");
}
}
}
});
System.out.println("Sorting by library:");
Collections.sort(list);
System.out.println("Sorting by own:");
Collections2.sort(list);
}
public static class Collections2 {
public static void sort(List<String> list) {
String element = list.remove(0);
list.add(element);
}
}
}
如您所见,我的自定义排列不会导致排列事件,因为它是通过删除和添加元素来完成的。如何实现自定义排列,从而导致排列事件
更新2
如果我尝试使用调试器跟踪排序,我将无法输入排序代码。一个非常简单的操作是对列表中的项目进行排序 例如,下面的代码将打印为true 对补充问题的答复:
我想自己做,而不调用黑盒方法。假设我有一个ObservableList实例,仅此而已,并且想编写一些操作代码,这会导致排列,我将如何做到这一点 如果您使用FXCollections util类提供的ObservableList,这是不可能的,因为ObservableList是在其中实现的 考虑到以下几点: 无论何时添加或删除图元,都会触发 检查getPermutation返回的int数组的长度是否大于零 在MappingChange的情况下,始终返回长度为0的int 现在,你一定像我一样想知道,当我们在同一个列表上排序时,它是如何工作的 事实证明,它是在FXCollections中创建列表的基础,会覆盖列表,然后强制执行 还有别的选择吗
您可以通过扩展来创建自己的自定义ObservableList,如所述和所示。要详细说明@ItachiUchiha的答案和@fabian的评论,任何修改ObservableList的操作都会通知更改侦听器。因此,无法通过调用一系列操作来触发ObservableList上的置换事件,每个操作都会修改列表,每个操作都会独立地通知侦听器 因此,要支持现成不支持的置换,即、、和,您需要实现自己的ObservableList,定义或可能重写触发置换的单个入口点方法。提供了一个方便的起点 下面是一个简单的例子:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import javafx.collections.ModifiableObservableListBase;
public class PermutatingObservableList<E> extends ModifiableObservableListBase<E> {
private final List<E> source ;
public PermutatingObservableList(List<E> source) {
this.source = source ;
}
public void permute(int[] permutation) {
checkPermutation(permutation);
beginChange();
List<E> temp = new ArrayList<>(source);
for (int i = 0 ; i < size() ; i++) {
source.set(i, temp.get(permutation[i]));
}
nextPermutation(0, size(), permutation);
endChange();
}
public void pairwiseSwap() {
int[] permutation = new int[size()];
for (int i = 0; i+1 < permutation.length ; i+=2) {
permutation[i] = i+1 ;
permutation[i+1] = i ;
}
if (permutation.length % 2 == 1) {
permutation[permutation.length - 1] = permutation.length - 1 ;
}
permute(permutation);
}
private void checkPermutation(int[] permutation) {
boolean valid = permutation.length == size();
Set<Integer> values = IntStream.range(0, size()).boxed().collect(Collectors.toSet());
for (int i=0; i<permutation.length && valid ; i++) {
valid = values.remove(new Integer(permutation[i]));
}
if (! valid) {
throw new IllegalArgumentException("Invalid permuation: "+Arrays.toString(permutation)+"\n"
+"Permutation must be same length as list and must contain each of the values "
+ "0-"+(size()-1)+" exactly once");
}
}
@Override
public E get(int index) {
return source.get(index);
}
@Override
public int size() {
return source.size();
}
@Override
protected void doAdd(int index, E element) {
source.add(index, element);
}
@Override
protected E doSet(int index, E element) {
return source.set(index, element);
}
@Override
protected E doRemove(int index) {
return source.remove(index);
}
}
我想到的最简单的排列是列表元素的排序。或者,我猜,shuffle也会导致这些事件:假设我想编写自己版本的shuffle。如果我在其中使用remove和add,我将永远不会导致排列。对于更新2中的注释,如果您试图了解Collections.sortlist的作用,它只会调用list.sortnull,请参阅。从FXCollections.observableArrayList返回的列表是非公共API的一个实例,它覆盖了sort以很好地管理事件。那么,sort如何导致这些事件呢?对ObservableList进行排序时,列表中的元素排列会发生变化。这将触发对ListChangeListener的通知。我希望自己触发它,而不调用黑盒方法。假设我有ObservalElist实例,仅此而已,并且想编写一些操作代码,这会导致排列,我该如何做呢?一般来说,FXCollections.sort应该优先于Collections.sort,但在这里它没有什么区别@造成事件本身的暗度有点棘手,因为在大多数情况下,这些事件的触发是自动处理的。最好的选择是手动扩展和触发事件。
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import javafx.collections.ModifiableObservableListBase;
public class PermutatingObservableList<E> extends ModifiableObservableListBase<E> {
private final List<E> source ;
public PermutatingObservableList(List<E> source) {
this.source = source ;
}
public void permute(int[] permutation) {
checkPermutation(permutation);
beginChange();
List<E> temp = new ArrayList<>(source);
for (int i = 0 ; i < size() ; i++) {
source.set(i, temp.get(permutation[i]));
}
nextPermutation(0, size(), permutation);
endChange();
}
public void pairwiseSwap() {
int[] permutation = new int[size()];
for (int i = 0; i+1 < permutation.length ; i+=2) {
permutation[i] = i+1 ;
permutation[i+1] = i ;
}
if (permutation.length % 2 == 1) {
permutation[permutation.length - 1] = permutation.length - 1 ;
}
permute(permutation);
}
private void checkPermutation(int[] permutation) {
boolean valid = permutation.length == size();
Set<Integer> values = IntStream.range(0, size()).boxed().collect(Collectors.toSet());
for (int i=0; i<permutation.length && valid ; i++) {
valid = values.remove(new Integer(permutation[i]));
}
if (! valid) {
throw new IllegalArgumentException("Invalid permuation: "+Arrays.toString(permutation)+"\n"
+"Permutation must be same length as list and must contain each of the values "
+ "0-"+(size()-1)+" exactly once");
}
}
@Override
public E get(int index) {
return source.get(index);
}
@Override
public int size() {
return source.size();
}
@Override
protected void doAdd(int index, E element) {
source.add(index, element);
}
@Override
protected E doSet(int index, E element) {
return source.set(index, element);
}
@Override
protected E doRemove(int index) {
return source.remove(index);
}
}
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import javafx.collections.ListChangeListener;
public class PermutingObservableListTest {
public static void main(String[] args) {
List<String> numbers = Arrays.asList("One", "Two", "Three", "Four", "Five");
PermutatingObservableList<String> list = new PermutatingObservableList<>(new ArrayList<>(numbers));
list.addListener(new ListChangeListener<String>() {
@Override
public void onChanged(Change<? extends String> c) {
while (c.next())
System.out.println(c.wasPermutated());
System.out.println(IntStream.range(0, list.size())
.map(c::getPermutation)
.mapToObj(Integer::toString)
.collect(Collectors.joining(", ")));
}
}
});
list.pairwiseSwap();
System.out.println(list);
}
}