简体   繁体   English

按名称对ArrayList项目进行排序

[英]Sort ArrayList items by name

I am trying to rearrange an ArrayList based on the name of the items to be on specific index. 我试图根据要在特定索引上的项目的名称重新排列ArrayList。

My list currently is this: 我的清单目前是这样的:

"SL"
"TA"
"VP"
"SP"
"PR"

and i want to rearrange them to: 我想将它们重新排列为:

"SL"
"SP"
"TA"
"PR"
"VP"

but based on the name and not in the index. 但基于名称而不是索引中。

I have tried this: 我已经试过了:

for (int i=0; i< list.size(); i++){
    if (list.get(i).getCategoryName().equals("SL")){
        orderedDummyJSONModelList.add(list.get(i));
    }
}
for (int i=0; i< list.size(); i++){
    if (list.get(i).getCategoryName().equals("SP")){
        orderedDummyJSONModelList.add(list.get(i));
    }
}
for (int i=0; i< list.size(); i++){
    if (list.get(i).getCategoryName().equals("TA")){
        orderedDummyJSONModelList.add(list.get(i));
    }
}
for (int i=0; i< list.size(); i++){
    if (list.get(i).getCategoryName().equals("PR")){
        orderedDummyJSONModelList.add(list.get(i));
    }
}
for (int i=0; i< list.size(); i++){
    if (list.get(i).getCategoryName().equals("VP")){
       orderedDummyJSONModelList.add(list.get(i));
    }
}

and it works fine, but i want to know if there is a more efficient way to do in 1 for loop or maybe a function. 它工作正常,但我想知道是否有一种更有效的方法可以在1 for循环或函数中执行。 I do not wish to do it like this: 我不希望这样:

orderedDummyJSONModelList.add(list.get(0));
orderedDummyJSONModelList.add(list.get(3));
orderedDummyJSONModelList.add(list.get(1));
orderedDummyJSONModelList.add(list.get(4));
orderedDummyJSONModelList.add(list.get(2));

Which also works. 这也有效。 Any ideas? 有任何想法吗?

You can use Collection.Sort method as Collection.Sort(list) since list is a List<String> you will be fine. 您可以将Collection.Sort方法用作Collection.Sort(list)因为listList<String> ,这样就可以了。 But if you want to implement a new comparator: 但是,如果要实现一个新的比较器:

Collections.sort(list, new NameComparator());

class NameComparator implements Comparator<String> { //You can use classes
    @Override
    public int compare(String a, String b) { //You can use classes
        return a.compareTo(b); 
    }
}

EDIT: 编辑:

You can define a class comparator for your needs: 您可以根据需要定义类比较器:

class ClassComparator implements Comparator<YourClass> { //You can use classes
    @Override
    public int compare(YourClass a, YourClass b) { //You can use classes
        return a.name.compareTo(b.name); 
    }
}

The key thing here is: you need to get clear on your requirements . 这里的关键是:您需要弄清需求

In other words: of course one can shuffle around objects stored within a list. 换句话说:当然,您可以在列表中存储的对象周围随机播放。 But: probably you want to do that programmatically . 但是:可能您想以编程方式执行此操作。

In other words: the correct approach is to use the built-in Collection sorting mechanisms, but with providing a custom Comparator. 换句话说:正确的方法是使用内置的Collection排序机制,但要提供自定义的 Comparator。

Meaning: you better find an algorithm that defines how to come from 含义:您最好找到一种定义如何得出的算法

"SL" "TA" "VP" "SP" "PR" “ SL”“ TA”“ VP”“ SP”“ PR”

to

"SL" "SP" "TA" "PR" "VP" “ SL”“ SP”“ TA”“ PR”“ VP”

That algorithm should go into your comparator implementation! 该算法应该进入比较器实现!

The point is: you have some List<X> in the first place. 重点是:首先有一些List<X> And X objects provide some sort of method to retrieve those strings you are showing here. X对象提供了某种方法来检索您在此处显示的那些字符串。 Thus you have to create a Comparator<X> that works on X values; 因此,您必须创建一个可以处理X值的Comparator<X> and uses some mean to get to those string values; 并使用一些均值来获取这些字符串值; and based on that you decide if X1 is <, = or > than some X2 object! 并据此确定X1是否比某些X2对象<,=或>!

  1. Use a hashmap to store the weight of all strings (Higher the value of the hashmap means the later this string should come in the final list). 使用哈希表存储所有字符串的权重(哈希表的值越高,表示该字符串应在最终列表中出现的时间越晚)。
  2. Using a Hashmap, so you can expand it later for other strings as well. 使用Hashmap,因此您以后也可以将其扩展为其他字符串。 It'll be easier to enhance in future. 将来会更容易进行增强。
  3. Finally, Use a custom Comparator to do it. 最后,使用自定义比较器执行此操作。

Required Setup: 所需的设置:

       List<String> listOfStrings = Arrays.asList("SL", "TA", "VP", "SP", "PR");

        HashMap<String, Integer> sortOrder = new HashMap<>();
        sortOrder.put("SL", 0);
        sortOrder.put("TA", 1);
        sortOrder.put("VP", 2);
        sortOrder.put("SP", 3);
        sortOrder.put("PR", 4);

Streams: 流:

        List<String> sortedList = listOfStrings.stream().sorted((a, b) -> {
            return Integer.compare(sortOrder.get(a), sortOrder.get(b));
        }).collect(Collectors.toList());

        System.out.println(sortedList);

Non-Stream: 非流:

        Collections.sort(listOfStrings, (a, b) -> {
            return Integer.compare(sortOrder.get(a), sortOrder.get(b));
        });
OR
        listOfStrings.sort((a, b) -> {
            return Integer.compare(sortOrder.get(a), sortOrder.get(b));
        });

        System.out.println(listOfStrings);

Output : 输出

[SL, TA, VP, SP, PR]

here´s an answer just specific for your problem working just for the given output. 这是仅针对您的问题的答案,仅适用于给定的输出。 If the List contains anything else this might break your ordering, as there is no rule given on how to order it and the PR just randomly appears in the end. 如果List包含其他内容,则可能会破坏您的订购,因为没有有关如何订购的规则, PR随即出现在最后。

public static void main(String[] args) {
    List<String> justSomeNoRuleOrderingWithARandomPRInside = new ArrayList<String>();
    justSomeNoRuleOrderingWithARandomPRInside.add("SL");
    justSomeNoRuleOrderingWithARandomPRInside.add("TA");
    justSomeNoRuleOrderingWithARandomPRInside.add("VP");
    justSomeNoRuleOrderingWithARandomPRInside.add("SP");
    justSomeNoRuleOrderingWithARandomPRInside.add("PR");
    java.util.Collections.sort(justSomeNoRuleOrderingWithARandomPRInside, new NameComparator());
    for(String s : justSomeNoRuleOrderingWithARandomPRInside) {
        System.out.println(s);
    }
}

static class NameComparator implements Comparator<String> { //You can use classes
    @Override
    public int compare(String a, String b) { //You can use classes
        // Lets just add a T in front to make the VP appear at the end 
        // after TA, because why not
        if (a.equals("PR")) {
            a = "T"+a;
        } else if(b.equals("PR")) {
            b = "T"+b;
        }
        return a.compareTo(b);
    }
}

O/P O / P

SL
SP
TA
PR
VP

But honestly, this solution is crap, and without any clear rule on how to order these this will be doomed to fail as soon as you change anything as @GhostCat tried to explain. 但老实说,这种解决方案是废话,并且在如何定购这些方法上没有任何明确的规则时,一旦您更改了任何内容(@GhostCat试图解释),它注定会失败。

How about this 这个怎么样

// define the order
List<String> ORDER = Arrays.asList("SL", "SP", "TA", "PR", "VP");

List<MyObject> list = ...
list.sort((a, b) -> {
    // lamba syntax for a Comparator<MyObject>
    return Integer.compare(ORDER.indexOf(a.getString()), ORDER.indexOf(b.getString());
});

Note that this will put any strings that aren't defined in the ORDER list at the start of the sorted list. 请注意,这会将未在ORDER列表中定义的所有字符串放在排序列表的开头。 This may or may not be acceptable - it may be worth checking that only valid strings (ie members of ORDER) appear as the result of MyObject.getString(). 这可能是可接受的,也可能是不可接受的-值得检查的是,只有有效的字符串(即ORDER的成员)才作为MyObject.getString()的结果出现。

You can build an index map using a LinkedHashMap . 您可以使用LinkedHashMap构建索引映射。 This will be used to lookup the order which to sort using the category names of your items. 这将用于查找使用商品类别名称排序的顺序。

ItemSorting 项目排序

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class ItemSorting {
    public static void main(String[] args) {
        List<Item> list = new ArrayList<Item>();
        IndexMap indexMap = new IndexMap("SL", "SP", "TA", "PR", "VP");
        ItemComparator itemComparator = new ItemComparator(indexMap);

        list.add(new Item("SL"));
        list.add(new Item("TA"));
        list.add(new Item("VP"));
        list.add(new Item("SP"));
        list.add(new Item("PR"));

        Collections.sort(list, itemComparator);

        for (Item item : list) {
            System.out.println(item);
        }
    }
}

ItemComparator ItemComparator

import java.util.Comparator;

public class ItemComparator implements Comparator<Item> {
    private IndexMap indexMap;

    public IndexMap getIndexMap() {
        return indexMap;
    }

    public void setIndexMap(IndexMap indexMap) {
        this.indexMap = indexMap;
    }

    public ItemComparator(IndexMap indexMap) {
        this.indexMap = indexMap;
    }

    @Override
    public int compare(Item itemA, Item itemB) {
        if (itemB == null) return -1;
        if (itemA == null) return 1;
        if (itemA.equals(itemB)) return 0;

        Integer valA = indexMap.get(itemA.getCategoryName());
        Integer valB = indexMap.get(itemB.getCategoryName());

        if (valB == null) return -1;
        if (valA == null) return 1;

        return valA.compareTo(valB);
    }
}

IndexMap 索引图

import java.util.LinkedHashMap;

public class IndexMap extends LinkedHashMap<String, Integer> {
    private static final long serialVersionUID = 7891095847767899453L;

    public IndexMap(String... indicies) {
        super();

        if (indicies != null) {
            for (int i = 0; i < indicies.length; i++) {
                this.put(indicies[i], new Integer(i));
            }
        }
    }
}

Item 项目

public class Item {
    private String categoryName;

    public Item(String categoryName) {
        super();
        this.categoryName = categoryName;
    }

    public String getCategoryName() {
        return categoryName;
    }

    public void setCategoryName(String categoryName) {
        this.categoryName = categoryName;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((categoryName == null) ? 0 : categoryName.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null) return false;
        if (getClass() != obj.getClass()) return false;
        Item other = (Item) obj;
        if (categoryName == null) {
            if (other.categoryName != null) return false;
        } else if (!categoryName.equals(other.categoryName)) return false;
        return true;
    }

    @Override
    public String toString() {
        return String.format("Item { \"categoryName\" : \"%s\" }", categoryName);
    }
}

Result 结果

Item { "categoryName" : "SL" }
Item { "categoryName" : "SP" }
Item { "categoryName" : "TA" }
Item { "categoryName" : "PR" }
Item { "categoryName" : "VP" }

You can create a Map that maintains the position. 您可以创建一个维持位置的地图。 When you iterate through the unordered list just get the position of that string value and insert into new array(not arraylist), then later if required you can convert that array to ArrayList. 当您遍历无序列表时,只需获取该字符串值的位置并插入新数组(而不是arraylist)中,然后在需要时可以将该数组转换为ArrayList。 Example code: 示例代码:

Map<String,Integer> map = new HashMap<>(); //you can may be loop through and make this map
map.put("SL", 0);
map.put("SP", 1);
map.put("TA",2);
map.put("PR",3);
map.put("VP",3);
List<String> list1 // your unordered list with values in random order
String[] newArr =  new String[list1.size()];
for(String strName: list1){
    int position  = map.get(strName);
    arr[position] = strName;
}
//newArr has ordered result.

You coud define a helper method like this one: 您可以定义一个像这样的辅助方法:

public static int get(String name) {
    switch (name) {
    case "SL":
        return 1;
    case "SP":
        return 2;
    case "TA":
        return 3;
    case "PR":
        return 4;
    case "VP":
        return 5;
    default:
        return 6;
    }
}

and write in your main method something like: 并在您的main方法中编写如下内容:

ArrayList<String> al = new ArrayList<>();
al.add("SL");
al.add("TA");
al.add("VP");
al.add("SP");
al.add("PR");
Collections.sort(al, (o1, o2) -> return get(o1) - get(o2); );
al.forEach((s) -> System.out.println(s));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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