我有两个ArrayList
个集合,我们称之为A
和B
。 A
是B
的子集,A
的元素少于B
(A
有大约10%的元素B
)。但是,A
中的元素的排序方式与它们在B
中的排序方式不同,我需要它们。
我可以想出一个算法,它会像在原始集合中那样对它们进行排序。我要问的是,如果有一些很好的方法,可能是JDK的一部分或Apache Commons的一部分。
答案 0 :(得分:2)
您需要一个比较器,根据较大列表中的索引比较较小列表中的对象。
实现这一点肯定有几种选择。
非常简单,但非常效率低的一种方法是创建一个比较器,用largerList.indexOf(element)
检查元素的索引。但除了最小的列表之外,所有这些都会有可怕的运行时间。
更复杂的解决方案是将映射从元素存储到较大列表中的索引,以便可以直接查找索引。这将显着显着更快,代价是Map
的一些额外存储空间。
这两种方法都是在这里实现的:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class SameOrderTest
{
public static void main(String[] args)
{
List<String> listA = new ArrayList<String>();
listA.add("S");
listA.add("A");
listA.add("M");
listA.add("P");
listA.add("L");
listA.add("E");
listA.add("W");
listA.add("O");
listA.add("R");
listA.add("D");
List<String> listB = new ArrayList<String>();
listB.add("A");
listB.add("M");
listB.add("S");
listB.add("E");
listB.add("L");
List<String> listB0 = new ArrayList<String>(listB);
Collections.sort(listB0, simpleSameOrderComparator(listA));
List<String> listB1 = new ArrayList<String>(listB);
Collections.sort(listB1, efficientSameOrderComparator(listA));
System.out.println("A : "+listA);
System.out.println("B0: "+listB0);
System.out.println("B1: "+listB1);
}
// WARNING: Simple but VERY inefficient
private static <T> Comparator<T> simpleSameOrderComparator(
final List<T> reference)
{
return new Comparator<T>()
{
@Override
public int compare(T t0, T t1)
{
return reference.indexOf(t0)-reference.indexOf(t1);
}
};
}
private static <T> Comparator<T> efficientSameOrderComparator(
final List<T> reference)
{
final Map<T, Integer> map = new LinkedHashMap<T, Integer>();
for (int i=0; i<reference.size(); i++)
{
map.put(reference.get(i), i);
}
return new Comparator<T>()
{
@Override
public int compare(T t0, T t1)
{
return map.get(t0)-map.get(t1);
}
};
}
}
我很好奇是否有一个解决方案不会影响排序算法的运行时间,并且不需要额外的存储空间。如果较小列表的大小仅为10%,则可能会反转查找并仅存储实际包含在较小列表中的元素的索引,但在这种情况下,运行时间将取决于列表和大小的比例,事先很难说这是否会有所回报。
m
和n
是列表的大小。
(EDIT2:根据评论更新)
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
public class SameOrderTest2
{
public static void main(String[] args)
{
List<String> listA = new ArrayList<String>();
listA.add("S");
listA.add("A");
listA.add("M");
listA.add("P");
listA.add("L");
listA.add("E");
listA.add("W");
listA.add("O");
listA.add("R");
listA.add("D");
List<String> listB = new ArrayList<String>();
listB.add("A");
listB.add("M");
listB.add("S");
listB.add("E");
listB.add("L");
List<String> listB0 = sorted(listA, listB);
System.out.println("A : "+listA);
System.out.println("B0: "+listB0);
}
private static <T> List<T> sorted(List<T> reference, List<T> toSort)
{
List<T> referenceList = new ArrayList<T>(reference);
referenceList.retainAll(new LinkedHashSet<T>(toSort));
return referenceList;
}
}
这还需要额外的存储,但是非常简洁和优雅,如果您可以为第二个列表创建新实例,而不必对其进行就地排序。< / p>
答案 1 :(得分:2)
您可以复制较大的集合,然后调用retainAll()
方法删除缺少的元素,保留顺序:
ArrayList result = new ArrayList(B).retainAll(A);
有效地,它会在您的收藏集A上调用contains()
,因此对于大型收藏集,Set
的效果会优于ArrayList
。