1

Guys I have final String of values which I am matching with values from DB. After matching I want string to appear in particular order, how can I customize this sort process or is there any other ways to achieve this. For more info please look into code below. Appreciated for help.

public static final String FRUITS ="Mango|Banana|Pear|Orange"; //want to maintain this order

List<String> retriveFruits= getFruitsDAO.fruitsList(); //this gets fruits from DB
List<String> afterSortList= new ArrayList<String>();

for(String names: retriveFruits){

    if(names.getKeyValue().matches(FRUITS)){
      afterSortList.add(names.getKeyValue());
    }
}

so after sorting names should maintian the order of Fruits ="Mango,Banana,Pear,Orange"; how do I achieve this

SwissCodeMen
  • 4,222
  • 8
  • 24
  • 34
user13079741
  • 122
  • 1
  • 10

4 Answers4

2

Assuming "Mango|Banana|Pear|Orange" fixed, I would go about it "like that":

import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.TreeSet;

public class Test {

    public static void main(String[] args) {
        System.out.println(sortIndiv());
    }
    // choose "richer" datastructure: fruit name as key, sort order as value:
    public static final Map<String, Integer> VALID_FRUITS = Map.of(
      "Mango", 0, 
      "Banana", 1,
      "Pear", 2,
      "Orange", 3);//want to maintain this order
    // Map.of(k,v,k,v,...) -> java >= 9

    // a "more generalized" result type: Collection<String>
    public static Collection<String> sortIndiv() {
        List<String> retriveFruits = Arrays.asList(
                new String[]{"Pear",
                    "Apple", "Banana", "Orange", "Mango", "Papaya"}
        ); // fix values for test purpose, otherwise ... dao.fruitList ...

        //here "the magic"...
        //A (self-sorting) TreeSet with a custom comparator
        //..using VALID_FRUITS:
        Collection<String> result = new TreeSet<>(new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return VALID_FRUITS.get(o1).compareTo(VALID_FRUITS.get(o2)); // == FRUITS.get(o1) - FRUITS.get(o2);
            }
        });

        // iterate: O(n)
        for (String fruit : retriveFruits) {
            // filter valids:
            if (VALID_FRUITS.containsKey(fruit)) {
                // add to result O(log(n))!
                result.add(fruit);
            }
            //so after sorting names should maintian the order final String Fruits ="Mango|Banana|Pear|Orange"; how do I achieve this
        }
        //done!
        return result;
    }
}

Output:

[Mango, Banana, Pear, Orange]

If Collection is not an acceptable return/result type (esp. when result contains/should contain duplicates, the TreeSet approach is not acceptable), then ArrayList and sort() can do the job comparably efficient (and allow duplicates):

import java.util.*;

public class Test {

    public static void main(String[] args) {

        List<String> retriveFruits = Arrays.asList(
                new String[]{"Pear",
                    "Apple", "Banana", "Orange", "Mango", "Papaya", "Mango", "Mango"}
        ); // dao.fruitList ...
        System.out.println(sortIndivSortedSet(retriveFruits));
        System.out.println(sortIndivQuickSort(retriveFruits));
    }
    public static final Map<String, Integer> VALID_FRUITS = Map.of("Mango", 0, "Banana", 1, "Pear", 2, "Orange", 3);
    //want to maintain this order

    private static Comparator<String> customComparator() {
        return new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return VALID_FRUITS.get(o1).compareTo(VALID_FRUITS.get(o2)); // == FRUITS.get(o1) - FRUITS.get(o2);
            }
        };
    }

    public static Collection<String> sortIndivSortedSet(List<String> retriveFruits) {
        Collection<String> result = new TreeSet<>(customComparator());
        for (String fruit : retriveFruits) {
            if (VALID_FRUITS.containsKey(fruit)) {
                result.add(fruit);
            }
        }
        return result;
    }

    public static List<String> sortIndivQuickSort(List<String> retriveFruits) {
       List<String> result = new ArrayList<>(retriveFruits.size());

       // O(n) 
        for (String fruit : retriveFruits) {
            if (VALID_FRUITS.containsKey(fruit)) {
                // x
                // O(1)
                result.add(fruit);
            }
        }
        // +
        // O(n log(n))
        result.sort(customComparator());
        return result;
    }
}

Ouput:

[Mango, Banana, Pear, Orange]
[Mango, Mango, Mango, Banana, Pear, Orange]
xerx593
  • 12,237
  • 5
  • 33
  • 64
  • Thanks for the great help @xerx593. This is indeed what I was looking for. – user13079741 Mar 23 '20 at 21:39
  • 1
    Welcome & thank you! :) From there (of course) you have many options, esp. the data structure of `VALID_FRUITS` ...there are many "structures", which can store a "string and an index" (...String[], List, Enum, ...) ...but(!): Map is (one of) the quickest regarding `containsKey`;) – xerx593 Mar 23 '20 at 21:48
  • ...even more significant: `Map.get(key)` is *way faster than* `List.indexOf(key)`;p – xerx593 Mar 23 '20 at 23:48
  • 1
    While it is true that `Map.get()` is faster than `List.indexOf()` (`O(1)` vs. `O(n)`), in a case like this it isn't significant. The `n` will never be large enough to matter speed-wise, because if it gets large enough a completely different solution should be sought (such as filtering and ordering the results directly in the database). But this is a good example showing how different collections can be used, as the crux of the algorithm is `Comparator` and a collection that can hold some kind of index (whether it's a list index or a `Map`). – Kayaman Mar 24 '20 at 09:19
  • ..I agree/assumed the same regarding `VALID_FRUITS` (`"n"` is small), but what about the `"m"`? (the size of input list) – xerx593 Mar 24 '20 at 09:26
  • We're still talking about *fruits* here. Since the output will be a list (or set) of ordered fruit names, it's micro-optimization. You would not write this kind of code in production anyway, but do it in the database where it would far outperform any Java solution. – Kayaman Mar 24 '20 at 09:47
2

Some simple method: First you just need a comparator where you define your order:

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

public class DefinedComparator implements Comparator<String> {
    List<String> definedOrder = // define your custom order
            Arrays.asList("Mango", "Banana", "Pear", "Orange");

    public int compare(String s1, String s2) {
        return Integer.valueOf(definedOrder.indexOf(s1)).compareTo(Integer.valueOf(definedOrder.indexOf(s2)));

    }
}

And let's say you have a list:

List<String> afterSortLIst= new ArrayList<String>();
        afterSortLIst.add("Orange");
        afterSortLIst.add("Mango");
        afterSortLIst.add("Banana");
        afterSortLIst.add("Pear");

And the list with comparator:

Collections.sort(afterSortLIst, new DefinedComparator());

The output will be:

[Mango, Banana, Pear, Orange]
Cleo
  • 136
  • 1
  • 10
2

If you replace the regular expression with a List of fruits, you can do it as follows

public static final List<String> FRUITS = Arrays.asList("Mango", "Banana", "Pear", "Orange");

List<String> retriveFruits= getFruitsDAO.fruitsList();
List<String> afterSortList= new ArrayList<String>();

for(String names: retriveFruits){

    if(fruits.contains(names.getKeyValue())){
      afterSortList.add(names.getKeyValue());
    }
}

afterSortList.sort(Comparator.comparingInt(FRUITS::indexOf));

From How to sort a List based on another List

The comparator transforms the elements to List indexes and essentially performs a sort of numbers 0, 1, 2, 3. As we know Comparator.compare(a, b) needs to return 0 for equal elements, negative if a < b and positive if a > b, therefore:

"Pear" "Pear"    -> compare(2, 2) = 0
"Banana" "Mango" -> compare(1, 0) = 1
"Pear" "Orange"  -> compare(2, 3) = -1

As can be seen from xerx593's answer, it's possible to use different kinds of collections to fulfill the algorithm, for example TreeSet to perform the sorting while adding, if duplicates aren't required, and a Map<String, Integer> to perform the lookup of the index which is done with List.indexOf() here.

The (theoretical) performance characteristics are discussed in the linked question, but this is the shorthand version. If performance is an actual measured concern, the filtering and sorting needs to be done in the database, which is designed exactly for the purpose of filtering and sorting (among other things).

Kayaman
  • 72,141
  • 5
  • 83
  • 121
0

you just need to use sort() function in java. first import:

import java.util.Arrays; 

and then simply DO:

Arrays.sort(afterSortLIst); 
sinammd
  • 122
  • 1
  • 1
  • 9