在Java中,如何根据另一个列表对一个列表进行排序?

Deb*_*cle 48 java sorting list arraylist

我已经看到了其他几个与此类似的问题,但我真的找不到能解决问题的任何问题.

我的用例是这样的:用户最初有一个项目列表(listA).他们重新排序项目并希望保持该顺序(listB),但是,由于限制我无法在后端保持订单,因此我必须在检索后对listA进行排序.

基本上,我有2个ArrayLists(listA和listB).一个具有特定顺序的列表应该在(listB)中,另一个具有项目列表(listA).我想基于listB对listA进行排序.

JB *_*zet 62

Collections.sort(listB, new Comparator<Item>() {
    public int compare(Item left, Item right) {
        return Integer.compare(listA.indexOf(left), listA.indexOf(right));
    }
});
Run Code Online (Sandbox Code Playgroud)

但这是非常低效的,您应该创建一个Map<Item, Integer>from listA来更快地查找项目的位置.

Guava有一个现成的比较器来做到这一点: Ordering.explicit()

  • 关于“Ordering”,这里有一个示例:“Collections.sort(listA, Ordering.explicit(listB))”。如果您现有的订单仅包含要排序的对象的字段(例如ID),请使用`onResultOf`:`Ordering.explicit(ids).onResultOf(item -&gt; item.getId())`。 (3认同)
  • O(n) 查找大约发生 O(nlogn) 次?那是 O(n^2 logn)!你没有开玩笑。 (2认同)
  • 注意Integer.compare仅在Java 7中可用。在Java 6或更低版本中,您需要使用Integer.valueOf(listA.indexOf(left))。compareTo(Integer.valueOf(listA.indexOf(right)))。 (2认同)

The*_*ech 40

Java 8:

Collections.sort(listToSort, 
    Comparator.comparing(item -> listWithOrder.indexOf(item)));
Run Code Online (Sandbox Code Playgroud)

或更好:

listToSort.sort(Comparator.comparingInt(listWithOrder::indexOf));
Run Code Online (Sandbox Code Playgroud)


rge*_*man 12

假设您有一个listB列表,用于定义要排序的顺序listA.这只是一个示例,但它演示了一个由列表定义的顺序,而不是数据类型的自然顺序:

List<String> listB = Arrays.asList("Sunday", "Monday", "Tuesday", "Wednesday",
    "Thursday", "Friday", "Saturday");
Run Code Online (Sandbox Code Playgroud)

现在,让我们说listA需要根据这个顺序进行排序.这是一个List<Item>,并Item有一个public String getWeekday()方法.

创建一个Map<String, Integer>将所有内容的值映射listB到可以轻松排序的内容,例如索引,即"Sunday"=> 0,...,"Saturday"=> 6.这将提供快速简便的查找.

Map<String, Integer> weekdayOrder = new HashMap<String, Integer>();
for (int i = 0; i < listB.size(); i++)
{
    String weekday = listB.get(i);
    weekdayOrder.put(weekday, i);
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以创建Comparator<Item>使用Map创建订单的自定义:

public class ItemWeekdayComparator implements Comparator<Item>
{
    private Map<String, Integer> sortOrder;

    public ItemWeekdayComparator(Map<String, Integer> sortOrder)
    {
        this.sortOrder = sortOrder;
    }

    @Override
    public int compare(Item i1, Item i2)
    {
        Integer weekdayPos1 = sortOrder.get(i1.getWeekday());
        if (weekdayPos1 == null)
        {
            throw new IllegalArgumentException("Bad weekday encountered: " +
               i1.getWeekday());
        }
        Integer weekdayPos2 = sortOrder.get(i2.getWeekday());
        if (weekdayPos2 == null)
        {
            throw new IllegalArgumentException("Bad weekday encountered: " +
               i2.getWeekday());
        }
        return weekdayPos1.compareTo(weekdayPos2);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以listA使用自定义排序Comparator.

Collections.sort(listA, new ItemWeekdayComparator(weekdayOrder));
Run Code Online (Sandbox Code Playgroud)


Fra*_*ank 9

JB Nizet答案的速度提升(来自他自己提出的建议).用这种方法:

  • 在我的单元测试中,对1000个项目列表进行100次排序可以提高速度10倍.

  • 在我的单元测试中,对10000个项目列表进行100次排序可以将速度提高140倍(整个批次为265毫秒而不是37秒).

当两个列表不相同时,此方法也将起作用:

/**
 * Sorts list objectsToOrder based on the order of orderedObjects.
 * 
 * Make sure these objects have good equals() and hashCode() methods or
 * that they reference the same objects.
 */
public static void sortList(List<?> objectsToOrder, List<?> orderedObjects) {

    HashMap<Object, Integer> indexMap = new HashMap<>();
    int index = 0;
    for (Object object : orderedObjects) {
        indexMap.put(object, index);
        index++;
    }

    Collections.sort(objectsToOrder, new Comparator<Object>() {

        public int compare(Object left, Object right) {

            Integer leftIndex = indexMap.get(left);
            Integer rightIndex = indexMap.get(right);
            if (leftIndex == null) {
                return -1;
            }
            if (rightIndex == null) {
                return 1;
            }

            return Integer.compare(leftIndex, rightIndex);
        }
    });
}
Run Code Online (Sandbox Code Playgroud)


小智 7

问题:根据另一个列表中存在的字段的所有可能值之一对 Pojo 列表进行排序。

看看这个解决方案,可能这就是你想要实现的:

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

public class Test {

  public static void main(String[] args) {
    List<Employee> listToSort = new ArrayList<>();
    listToSort.add(new Employee("a", "age11"));
    listToSort.add(new Employee("c", "age33"));
    listToSort.add(new Employee("b", "age22"));
    listToSort.add(new Employee("a", "age111"));
    listToSort.add(new Employee("c", "age3"));
    listToSort.add(new Employee("b", "age2"));
    listToSort.add(new Employee("a", "age1"));

    List<String> listWithOrder = new ArrayList<>();
    listWithOrder.add("a");
    listWithOrder.add("b");
    listWithOrder.add("c");

    Collections.sort(listToSort, Comparator.comparing(item -> 
    listWithOrder.indexOf(item.getName())));
    System.out.println(listToSort);
  }

}


class Employee {
  String name;
  String age;

  public Employee(String name, String age) {
    super();
    this.name = name;
    this.age = age;
  }

  public String getName() {
    return name;
  }

  public String getAge() {
    return age;
  }

  @Override
  public String toString() {
    return "[name=" + name + ", age=" + age + "]";
  }
}
Run Code Online (Sandbox Code Playgroud)

输出 [[name=a, age=age11], [name=a,age=age111], [name=a,age=age1], [name=b,age=age22], [name=b,age=age2 ],[姓名=c,年龄=年龄33],[姓名=c,年龄=年龄3]]


Axo*_*ren 6

这是一种解决方案,可以增加时间复杂度2n,但可以实现您想要的效果.它也不关心R您要排序的List 是否包含Comparable元素,只要L您用来对其进行排序的其他List 是统一的Comparable.

public class HeavyPair<L extends Comparable<L>, R> implements Comparable<HeavyPair<L, ?>> {
    public final L left;
    public final R right;

    public HeavyPair(L left, R right) {
        this.left = left;
        this.right = right;
    }

    public compareTo(HeavyPair<L, ?> o) {
        return this.left.compareTo(o.left);
    }

    public static <L extends Comparable<L>, R> List<R> sort(List<L> weights, List<R> toSort) {
        assert(weights.size() == toSort.size());
        List<R> output = new ArrayList<>(toSort.size());
        List<HeavyPair<L, R>> workHorse = new ArrayList<>(toSort.size());
        for(int i = 0; i < toSort.size(); i++) {
            workHorse.add(new HeavyPair(weights.get(i), toSort.get(i)))
        }
        Collections.sort(workHorse);
        for(int i = 0; i < workHorse.size(); i++) {
            output.add(workHorse.get(i).right);
        }
        return output;
    }
}
Run Code Online (Sandbox Code Playgroud)

但请原谅我在编写此代码时使用的任何可怕做法.我匆匆忙忙.

打电话吧 HeavyPair.sort(listB, listA);

编辑:修正了这一行return this.left.compareTo(o.left);.现在它确实有效.


Khi*_*nsu -1

如果对象引用应该相同,则可以将listA初始化为新的。

listA = new ArrayList(listB)
Run Code Online (Sandbox Code Playgroud)