ListChangeListener was Permutated block

The JavaDoc for ListChangeListener provides a template for handling changes. However, I do not know how to handle permutations. For each index, I can find out where the new index of the element is located, but I do not know what to do with it. This is a bit of a puzzle that is independent of the programming language. ObservableList can add (), remove (), set (), and also has an iterator.

If I have the original list [1,2,3] and the list [] are attached to it, the linked list [1,2,3] should correspond to it. If the source list gets its comparator, replaced so that the source list now reads [3,2,1], how can I make a linked list?

/** * Binds a source list elements to a destination list. Any changes made in * the source list will reflect in the destination list. * * @param <SRC> The source list object type. * @param <DEST> The destination list object type. * @param dest The destination list that will be bound to the src list. * @param src The source list to watch for changes, and propagate up to the * destination list. * @param transformer A function that will transform a source list data * type, A, into a destination list data type, B. */ public static <SRC, DEST> void bindLists( ObservableList<DEST> dest, ObservableList<SRC> src, Function<? super SRC, ? extends DEST> transformer) { /*Add the initial data into the destination list.*/ for (SRC a : src) { dest.add(transformer.apply(a)); } /*Watch for future data to add to the destination list. Also watch for removal of data form the source list to remove its respective item in the destination list.*/ src.addListener((ListChangeListener.Change<? extends SRC> c) -> { while (c.next()) { if (c.wasPermutated()) { /*How do you handle permutations? Do you remove and then add, or add and then remove, or use set, or use a copy arraylist and set the right indices? Removing/adding causes concurrent modifications.*/ for (int oldIndex = c.getFrom(); oldIndex < c.getTo(); oldIndex++) { int newIndex = c.getPermutation(oldIndex); dest.remove(oldIndex); dest.add(newIndex, dest.get(oldIndex)); } } else if (c.wasUpdated()) { } else { /*Respond to removed data.*/ for (SRC item : c.getRemoved()) { int from = c.getFrom(); dest.remove(from); } /*Respond to added data.*/ for (SRC item : c.getAddedSubList()) { int indexAdded = src.indexOf(item); dest.add(indexAdded, transformer.apply(item)); } } } }); } 
+6
source share
2 answers

In the case of permutation, I would not try to use add() and remove() for processing. This will make the indexes move and will confuse things (at least for me).

Conceptually, what you get is a range of affected elements and an array containing some numbers indicating where each element was moved. I think you understand so much. In your code you have

  newIndex = getPermutation(oldIndex); 

which means that the item was in oldIndex , you need to move it to newIndex . The wrinkle is that if you just do the movement directly, you can rewrite the element that has not yet been moved. I think the easiest way to handle this is to make a copy of the affected sub-range, and then just go through the permutation array and move the elements from the copy to their new positions. Code for this:

  int from = c.getFrom(); int to = c.getTo(); List<DEST> copy = new ArrayList<>(dest.subList(from, to)); for (int oldIndex = from; oldIndex < to; oldIndex++) { int newIndex = c.getPermutation(oldIndex); dest.set(newIndex, copy.get(oldIndex - from)); } 

This is a permutation, so each element ends somewhere, and not one is added or removed. This means that you don’t need to copy the range of the list, and you can move the elements one by one behind the chain of moves, using only one element of the temporary space. There may be several loop cycles, so you will also have to detect and process them. That sounds pretty complicated. I will leave this for the other respondent. :-) For my money, copying the affected range is simple and easy to understand.

Swapping and updated change modes are not triggered by normal list actions. If you look at javafx.collections.ObservableListBase , you will see a protocol that the list implementation can use to create information about a specific change. If the implementation provides the correct information to the nextPermutation or nextUpdate , this will cause these other other change modes. I am not sure what might call them in JavaFX. For example, the Node.toFront() and Node.toBack() methods for changing the stacking order of a node can potentially generate permutation changes, but they do not look. I don’t know anything about what might cause the update to change.

Semantically, I think that changing the update implies that the elements in this range of the list have changed, but the length of the list will remain the same. This contradicts the β€œreplaced” change mode, where the range of elements can be replaced with a different number of elements. It may also be that changing the update means that the elements themselves have not been replaced - that is, the contents of the list have not changed - the internal state of the elements has simply changed.

+6
source

Please note that what you do here is implemented in EasyBind . See how map and bind list.

Essentially, this is how you implement your bindLists method:

 public static <SRC, DEST> void bindLists( ObservableList<DEST> dest, ObservableList<SRC> src, Function<? super SRC, ? extends DEST> transformer) { EasyBind.listBind(dest, EasyBind.map(src, transformer)); } 
+2
source

Source: https://habr.com/ru/post/974926/


All Articles