2

I have a JTable which contains TableModel(all my data). The JTable has multiple rows and columns. I need to shuffle the rows randomly. I understand I can do that with

Collections.shuffle(some list from TableModel);

But I dont know how to get the list from the existing JTable which had TableModel.

on somebodies suggestion, I tried this

RowSorter<? extends TableModel> sorter = mDocListTable.getRowSorter();
    ArrayList<RowSorter.SortKey> list = new ArrayList<RowSorter.SortKey>();

    list.add(new RowSorter.SortKey(0, SortOrder.DESCENDING));

    Collections.shuffle(list);
    sorter.setSortKeys(list);

but didnt work.

user1631306
  • 4,350
  • 8
  • 39
  • 74
  • 1
    I believe one approach would be to create a custom [`RowSorter`](https://docs.oracle.com/javase/7/docs/api/javax/swing/RowSorter.html). `RowSorter` was designed with the intent of using a column header as a sort key, so there's some excess overhead that you won't necessarily need, but the `convertRowIndexToModel(int index)` and `convertRowIndexToView(int index)` methods should do what you want; simply creating a mapping of the list of integers `[0, 1, ..., getRowCount()]`, to the same integers but shuffled. The convert to view method would return the mapped value. – Ironcache Jun 21 '16 at 17:22
  • Though if you actually want the table in the model modified (not just the view), you could also just use `moveRow(int start, int end, int to)` in [`DefaultTableModel`](https://docs.oracle.com/javase/7/docs/api/javax/swing/table/DefaultTableModel.html). – Ironcache Jun 21 '16 at 17:27
  • can you please elaborate on "simply creating a mapping of the list of integers [0, 1, ..., getRowCount()], to the same integers but shuffled". a small example would help – user1631306 Jun 21 '16 at 17:27

1 Answers1

2

Something like this could work?

DefaultTableModel model = (DefaultTableModel) table.getModel();
model.getDataVector().sort((Object o1, Object o2) -> Math.random() > 0.5 ? -1 : 1);
model.fireTableDataChanged();

Edit:

For Java-7 and since .sort() was not implemented until Java-8, a 2nd (and maybe more readable) option could be:

DefaultTableModel model = (DefaultTableModel) table.getModel();
Collections.shuffle(model.getDataVector());
model.fireTableDataChanged();

This cannot be reverted.

Alex S. Diaz
  • 2,637
  • 2
  • 23
  • 35
  • This is better than my answer was. I've deleted my answer, and recommend this instead. – Ironcache Jun 21 '16 at 17:57
  • Do note though that this requires a version of Java that supports Lambda expressions (IE: Java 8). – Ironcache Jun 21 '16 at 17:59
  • What would be Object o1, Object o2 – user1631306 Jun 21 '16 at 18:28
  • @user1631306 the rows to be compared by the `Comparator`, but since you just need a random result, you don't need it I guess – Alex S. Diaz Jun 21 '16 at 18:35
  • a.getDataVector().sort((null) -> Math.random() > 0.5 ? -1 : 1); like this? – user1631306 Jun 21 '16 at 18:39
  • 1
    @user1631306 Those are the parameters of the [lambda expression](https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html) implementation of the [`Comparator`](https://docs.oracle.com/javase/8/docs/api/java/util/Comparator.html) being passed into the `sort` method. Basically, any functional interface (Interfaces containing 1 method annotated with @FunctionalInterface) can be implemented using lambda expressions, which take the form of `(Args) -> action`. It simply prevents you from having to create new anonymous inner objects (less verbose). – Ironcache Jun 21 '16 at 18:43
  • 1
    You will still need to pass in the objects: `.sort((null) -> ...` will not work. What's happening here is that the method `sort(T t1, T t2)` is being defined by the lambda expression (where `T` is of type `Object` in this case). I recommend taking a look into the [`@FunctionalInterface`](https://docs.oracle.com/javase/8/docs/api/java/lang/FunctionalInterface.html) annotation Javadoc (which `Comparator` uses, and hence allows the lambda expression to be defined in `sort()`). – Ironcache Jun 21 '16 at 18:46
  • it seems complicated to me. can we talk on chat? – user1631306 Jun 21 '16 at 18:48
  • I'm unable to chat currently unfortunately. Also, I'm realizing I misspoke above; it should read `sort(Comparator)`, not `sort(T t1, T t2)`. That's probably not helping the confusion. – Ironcache Jun 21 '16 at 18:54
  • Let me rewind; I might've made this way more complicated than it needs to be. Lambda expressions provide the ability to dynamically implement single-method interfaces using less verbosity. Where it says `(Object o1, Object o2) -> Math.random() > 0.5 ? -1 : 1` above, that's the **exact same** as saying `new Comparator() { @Override public int compare(Object o1, Object o2) {return Math.random() > 0.5 ? -1 : 1}}` you could instead use the latter if you're more comfortable with that. – Ironcache Jun 21 '16 at 19:02
  • Here's an [example](https://ideone.com/Nw7Bfw) that hopefully can make that clear. – Ironcache Jun 21 '16 at 19:12
  • unfortunately, I am using java 7 and cant move to 8 right now – user1631306 Jun 21 '16 at 19:26
  • @user1631306 added java 7 equivalent, also, in Ironcache example there is a Java8/java7 equivalent of this – Alex S. Diaz Jun 21 '16 at 19:29
  • Actually, looking at it now, `sort()` wasn't added to `Vector` until Java 8 (see [Java 7 Javadoc](https://docs.oracle.com/javase/7/docs/api/java/util/Vector.html) vs. [Java 8 Javadoc](https://docs.oracle.com/javase/8/docs/api/java/util/Vector.html)). Instead of using `model.getDataVector().sort(...)`, you would need to use `Collections.sort(model.getDataVector(), ...)`, where `...` is kept the same in both cases, and `Collections` is coming from Guava. – Ironcache Jun 21 '16 at 20:05
  • I used Java-7 one, but I dont see any changes in the order of the elements of the model, before and after shuffling. I checked the content of model by model.getValueAt(3, 3) and they are same. – user1631306 Jun 22 '16 at 11:57
  • [Works fine for me](https://ideone.com/wvP2rG). Did you try it multiple times? Shuffling could very easily result in content ending up in the same place. Also, make sure you put in the `model.fireTableDataChanged()` call; it lets the `JTable` know that the `TableModel` changed. – Ironcache Jun 22 '16 at 16:46
  • When I check model.getDataVector().isEmpty(), it returns true to me. Though I am able to get that data is I do model.getValueAt(3, 3) and all... Also, I have AbstractTableModel and I am casting it to defaultTableModel – user1631306 Jun 22 '16 at 17:26
  • I'd recommend posting an [MCVE](http://stackoverflow.com/help/mcve) that illustrates the behavior you're seeing. I can't reproduce it, and the answer as listed works for me, so I can't really help you get further without knowing more about the problem. – Ironcache Jun 22 '16 at 17:41