简体   繁体   中英

Java sort based on keywords

I have a list of vehicles. I want to sort theses vehicles based on the make. Order is deined in another array.

This code sorts well with an array of two makes, "Honda" and "Kia". This sorts with Honda on top of Kia on top of the rest. Is it possible to make it generic for an array that would change in size. What if the array was "Chevrolet","Dodge","Ford"?

Thanks

//This sorts Honda first, Kia second, and others after.
final String[] makes = new String[]{"Honda","Kia"};
Collections.sort(vehicles, new Comparator<Vehicle>() {
    @Override
    public int compare(Vehicle o1, Vehicle o2) {
        String makeObj1 = o1.getModel().getMakeName().toLowerCase();
        String makeObj2 = o2.getModel().getMakeName().toLowerCase();
        //honda first
        if (makeObj1.equals(makes[0].toLowerCase())) {
            if (makeObj2.equals(makes[0].toLowerCase())) {
                return 0;//honda = honda
            }
            if (makeObj2.equals(makes[1].toLowerCase())) {
                return -1;//honda > kia
            } else {
                return -1;//honda > others
            }
        }
        //kia first
        if (makeObj1.equals(makes[1].toLowerCase())) {
            if (makeObj2.equals(makes[0].toLowerCase())) {
                return 1;//kia < honda
            }
            if (makeObj2.equals(makes[1].toLowerCase())) {
                return 0;//kia = kia
            } else {
                return -1;//kia > others
            }
        }
        //honda second
        if (makeObj2.equals(makes[0].toLowerCase())) {
            if (makeObj1.equals(makes[1].toLowerCase())) {
                return 1;//kia < honda
            } else {
                return 1;//other < honda
            }
        }
        //kia second
        if (makeObj2.equals(makes[1].toLowerCase())) {
            return 1;//others < kia
        }
        return 0;//all cases should been covered
    }
});

Didn't test it, but you could try:

public int compare(Vehicle o1, Vehicle o2) {

    String makeObj1 = o1.getModel().getMakeName().toLowerCase();
    String makeObj2 = o2.getModel().getMakeName().toLowerCase();

    int indexMake1 = Arrays.asList(makes).indexOf(makeObj1);
    int indexMake2 = Arrays.asList(makes).indexOf(makeObj2);

    if (indexMake1 == -1) indexMake1 = makes.length;
    if (indexMake2 == -1) indexMake2 = makes.length;

    return indexMake1 - indexMake2;
}

A possible solution (if you don't want to use the Collections.sort) can be to use Key index counting where the brands of the cars are the keys (buckets).

Ref: http://www.cs.princeton.edu/courses/archive/spr13/cos226/demo/51DemoKeyIndexedCounting.pdf

Quick implementation example:

public class Vehicle {
    private String m_name;
    private String m_brand;

    public Vehicle(String name, String brand)  {
        m_name = name;
        m_brand = brand;
    }

    public String getBrand() {
        return m_brand;
    }

    @Override
    public String toString()  {
        return "Vehicle: " + m_name + " - " + m_brand;
    }
}


public class KeyIndexCounting 
{
    public void sort(ArrayList<Vehicle> input, ArrayList<String> rules)
    {
        int N = input.size();
        int R = rules.size();
        int[] count = new int[R + 1];
        Vehicle[] aux = new Vehicle[N];

        for(int i = 0; i < N; ++i)
        {
            String brand = input.get(i).getBrand();
            ++count[rules.indexOf(brand) + 1];
        }

        for(int r = 0; r < R; ++r)
            count[r + 1] += count[r];

        for(int i = 0; i < N; ++i)
        {
            String brand = input.get(i).getBrand();
            aux[count[rules.indexOf(brand)]++] = input.get(i);
        }

        for(int i = 0; i < N; ++i)
            System.out.println(aux[i]); // Print sorted output array
    }
}

Usage:

    KeyIndexCounting key = new KeyIndexCounting();

    ArrayList<Vehicle> v = new ArrayList<>();
    v.add(new Vehicle("A", "Kia"));
    v.add(new Vehicle("B", "Honda"));
    v.add(new Vehicle("C", "Mazda"));
    v.add(new Vehicle("D", "Kia"));
    v.add(new Vehicle("E", "Honda"));
    v.add(new Vehicle("F", "Mercedes"));
    v.add(new Vehicle("G", "Porsche"));
    v.add(new Vehicle("H", "Honda"));
    v.add(new Vehicle("I", "Kia"));

    ArrayList<String> b = new ArrayList<>();
    b.add("Kia");
    b.add("Mercedes");
    b.add("Honda");
    b.add("Porsche");
    b.add("Mazda");

    key.sort(v, b);

Output:

Vehicle: A - Kia
Vehicle: D - Kia
Vehicle: I - Kia
Vehicle: F - Mercedes
Vehicle: B - Honda
Vehicle: E - Honda
Vehicle: H - Honda
Vehicle: G - Porsche
Vehicle: C - Mazda

EDIT: A version which takes just puts all vehicles from brands which don't appear in the "rules" arraylist, at the end:

    int N = input.size();
    int R = rules.size();
    int[] count = new int[R + 1];
    Vehicle[] aux = new Vehicle[N];

    int others = aux.length - 1;

    for(int i = 0; i < N; ++i)
    {
        String brand = input.get(i).getBrand();
        int index = rules.indexOf(brand);
        if(index != -1)
            ++count[index + 1];
        else
            aux[others--] = input.get(i);
    }

    for(int r = 0; r < R; ++r)
        count[r + 1] += count[r];

    for(int i = 0; i < N; ++i)
    {
        String brand = input.get(i).getBrand();
        int index = rules.indexOf(brand);
        if(index != -1)
            aux[count[index]++] = input.get(i);
    }

    for(int i =0; i < N; ++i)
        System.out.println(aux[i]);

    System.out.println("Unsorted vehicles: " + others);

Usage:

    KeyIndexCounting sort = new KeyIndexCounting();

    ArrayList<Vehicle> v = new ArrayList<>();
    v.add(new Vehicle("A", "Kia"));
    v.add(new Vehicle("B", "Honda"));
    v.add(new Vehicle("C", "Mazda"));
    v.add(new Vehicle("D", "Kia"));
    v.add(new Vehicle("E", "Honda"));
    v.add(new Vehicle("F", "Mercedes"));
    v.add(new Vehicle("G", "Porsche"));
    v.add(new Vehicle("H", "Honda"));
    v.add(new Vehicle("I", "Kia"));

    ArrayList<String> b = new ArrayList<>();
    b.add("Mazda");
    b.add("Kia");
    b.add("Mercedes");

Output:

Vehicle: C - Mazda
Vehicle: A - Kia
Vehicle: D - Kia
Vehicle: I - Kia
Vehicle: F - Mercedes
Vehicle: H - Honda
Vehicle: G - Porsche
Vehicle: E - Honda
Vehicle: B - Honda
Unsorted vehicles: 4

As you can see, the last 4 vehicles are unsorted because both Honda and Porsche did not appear in the list.

I made this work and it's quite simple, but I'd give a look at @ultddave first.

Here's my code :

Collections.sort(vehicles, new Comparator<Vehicle>() {
    @Override
    public int compare(Vehicle o1, Vehicle o2) {
        if (o1 == null && o2 == null) {
            return 0;
        }
        if (o1 == null) {
            return -1;
        }
        if (o2 == null) {
            return 1;
        }
        //honda first

        for (int i = 0; i < makes.length; i++) {
            for (int j = 0; j < makes.length; j++) {
                String str1 = o1.getModel().getMakeName().toLowerCase();
                String str2 = o2.getModel().getMakeName().toLowerCase();
                if (i < j) {
                    if (str1.equals(makes[i].toLowerCase())) {
                        return -1;
                    }
                    if (str2.equals(makes[i].toLowerCase())) {
                        return 1;
                    }
                } else if (i == j) {
                    if (str1.equals(makes[i].toLowerCase()) && str2.equals(makes[j].toLowerCase())) {
                        return 0;
                    }
                } else {
                    if (str1.equals(makes[i].toLowerCase())) {
                        return 1;
                    }
                    if (str2.equals(makes[i].toLowerCase())) {
                        return -1;
                    }
                }
            }
        }
        return 0;
    }
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM