按照数组中的值对对象列表进行排序。

3

我有一个包含1000多个项目的列表List<Brand> categories;

对于列表中的每个项目,我都有一个id,我使用categories.getId();来获取它。

我还有一个数组int[] sortedIdArr = {4,53,102,403,110,5,6,8,12};

我想按照sortedIdArr中的顺序对categories列表进行排序并按照id排序。如何实现?

private void sortBrandsById(List<Brand> categories) {
    Collections.sort(categories, new Comparator<Brand>() {
        public int compare(Brand o1, Brand o2) {

        }
    });    
}

我可以使用 Collections.sort 吗?


2
检查 sortedIdArr 中两个 ID 的索引,并比较这些索引。如果 o1-ID 的索引小于 o2-ID,则应该返回 1,如果更小则返回 -1,如果相等则返回 0 - Tom
4个回答

2
通常情况下,您可以使用Collections.sort或Java 8中的等效惯用语,或者使用已排序的Collection例如TreeSet然而,在这种情况下,您想要遵循一个预定义的顺序,由您的sortedIdArr数组所指定。 一种实现方法是使用链接集合(例如LinkedHashSet)。
然后,您遍历sortedIdArr数组,并在您的List<Brand>中搜索具有给定ID的对象。
如果找到,您将具有给定ID的Brand对象添加到您的LinkedHashSet,该集合将保留插入顺序。
请注意,如果未找到ID,则您的Set将不完全与该数组"匹配"。 使用Java 8的自包含示例:
package test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;


public class Main {

    // simplified Brand pojo
    static class Brand {
        int id;
        public Brand(int id) {
            this.id = id;
        }
        public int getId() {
            return id;
        }

        // for output clarity
        @Override
        public String toString() {
            return String.format("Brand: %d", id);
        }
    }

    public static void main(String[] args) throws Exception {

        // simplified ID list
        int[] sortedIdArr = {4,53,102};
        // "randomly" ordered Brand list
        final List<Brand> categories = new ArrayList<Brand>() {  
            {
                add(new Brand(1));
                add(new Brand(102));
                add(new Brand(53));
                add(new Brand(4));
                add(new Brand(0));
            }
        };
        // destination: linked set
        Set<Brand> linked = new LinkedHashSet<Brand>();
        // streaming the ID array in order
        Arrays.stream(sortedIdArr)
            .forEach((i) -> {
                // retrieving a Brand with same ID as the current
                // from the "randomly" ordered list
                Optional<Brand> toAdd = categories.stream()
                .filter((b) -> b.getId() == i)
                .findFirst();
                // making sure there's one
                if (toAdd.isPresent()) {
                    // adding to linked set
                    linked.add(toAdd.get());
                }
            }
        );
        System.out.println(linked);
    }

}

输出

[Brand: 4, Brand: 53, Brand: 102]

旧版Java的命令式语法

for (int i: sortedIdArr) {
    for (Brand b: categories) {
        // assuming no nulls
        if (b.getId() == i) {
            linked.add(b);
            break;
        }
    }
}

不错的方法,但是能否避免使用Java 8呢?我在Android中使用这段代码,目前存在Java 8的问题。 - VLeonovs
@VLeonovs 如果你在使用Android,那么你可以忘记Java 8的习惯用法了 :) 但是你可以相对容易地将其转换为Java 6风格的方法 - 参见我的编辑。 - Mena

1

是的,您可以使用Collections.sort()来排序。

id对您的Brand进行排序:

public int compare(Brand o1, Brand o2) {
   return o1.getId().compareTo(o2.getId());
}

使用 id 数组 sortedIdArr 对你的 Brand 进行排序:

实现 Comparator 类:

class C implements Comparator<A> {

    int[] idOrder;

    public C(int[] idOrder) {
        super();
        this.idOrder = idOrder;
    }

    @Override
    public int compare(A o1, A o2) {

        Integer indexofO1 = Arrays.binarySearch(idOrder, o1.getId());
        Integer indexofO2 = Arrays.binarySearch(idOrder, o2.getId());
        return indexofO1.compareTo(indexofO2);
    }
}

这里的关键思想是反转过程,使用id的索引而不是id本身进行比较!

使用方法:

Collections.sort(list, new C (idOrder));

测试例子:
int[] idOrder = new int [] {3,1,2};
List<A> list = new ArrayList<>();

list.add(new A(1));
list.add(new A(2));
list.add(new A(3));

System.out.println(list);
//Output : [A [id=1], A [id=2], A [id=3]]

Collections.sort(list, new C(idOrder));

System.out.println(list);
//Output : [A [id=3], A [id=1], A [id=2]]

2
他想按照sortedIdArr中的id顺序对类别列表进行排序。您的方法按升序对品牌ID属性进行排序,与sortedIdArr中列出的ID顺序无关。 - STaefi
谢谢大家,我更新了我的答案来解决sortedIdArr问题 :) .. 你可以检查一下。 - Wael Sakhri

1
你可以使用 Collections.sort(...) 来实现,但是我强烈建议在列表中有这么多项的情况下不要使用 Comparator 方法。
你可以在 List<Brand> categories 上循环,并将它们添加到名为 tempMap 的 HashMap<Integer,Brand> 中。然后使用它按照 sortedIdArr 数组的顺序进行查找。更改你的排序方法如下:
private void sortBrandsById(List<Brand> categories, int [] sortedIdArr) {
    HashMap<Integer,Brand> tempMap = new HashMap<Integer, Brand>(categories.size());
    for (int i = 0; i < categories.size(); i++) {
        tempMap.put(categories.get(i).getId(), categories.get(i));
    }
    categories = new ArrayList<Brand>(sortedIdArr.length);
    for (int i = 0; i < sortedIdArr.length; i++) {
        categories.add(tempMap.get(sortedIdArr[i]));
    }
}

这种排序方式的时间复杂度为O(n),其中包括创建tempMapO(n)和重新生成category列表的O(n)。虽然HashMap的get/put操作并不能保证O(1)的时间复杂度,但是Java的哈希实现非常好且可靠。因此,总的时间复杂度不会比O(n)更高。至少它比O(n^2)要好得多。时间复杂度非常重要,我认为你很难找到比O(n)更好的方法。希望这能有所帮助。

0
您可以使用以下代码(您需要Apache Commons Lang jar包,否则您必须迭代遍历数组以查找索引)。
private static void sortBrandsById(List<Brand> categories,int[] array) {


            Collections.sort(categories, new Comparator<Brand>() {
                public int compare(Brand o1, Brand o2) {                            

    return ArrayUtils.indexOf(array,o1.getId())-ArrayUtils.indexOf(array,o2.getId());
                }
            });    
        }

如果您能够将预定义的排序顺序放入列表而不是数组中,那么这将更加容易。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接