我有一个对象列表。那些对象(以及其他)有一个私有的int数组(如果它有帮助,我可以将它转移到List中)。这个数组有一个公共Getter。所有阵列的大小都相同。
我想根据它们的数组对Object进行排序:
Unsorted:
{[0, 1, 4, 5],
[0, 0, 2, 3],
[0, 1, 1, 2]}
Sorted:
{[0, 0, 2, 3],
[0, 1, 1, 2],
[0, 1, 4, 5]}
用词(称为词典编纂):
我设法搜索它们,例如只有具有普通比较器的数组的第一个元素,但我不知道如何搜索它们。
答案 0 :(得分:12)
一个不错的Java 8解决方案
static final Comparator<CustomObject> COMPARATOR = (o1, o2) -> {
int[] arr1 = o1.getArray();
int[] arr2 = o2.getArray();
return IntStream.range(0, arr1.length)
.map(i -> Integer.compare(arr1[i], arr2[i]))
.filter(i -> i != 0)
.findFirst()
.orElse(0);
};
然后,给定List<CustomObject>
,您可以
list.sort(COMPARATOR);
(Comparator
仅适用于相同长度的数组。您可能需要修改它。)
答案 1 :(得分:8)
我有一个对象的集合(最好是某种列表) [...] 现在我想根据它们的数组对对象进行排序
要使它有意义,有问题的Collection
必须是保留顺序并允许您重新排序元素的List
。就高级集合界面而言,只有Collection
具有所需的属性,因此我们假设您的List
确实是List
。
对Collections.sort()
进行排序的标准方法是使用两种Comparable
方法之一。一个要求列表元素实现Comparator
,而另一个更通用的要求你提供一个实现Comparable
的对象,用于确定对象的所需相对顺序。
数组不实现Comparator
(这相当于说它们没有&#34;自然顺序&#34;),但是包含它们的对象的类可以这样做。但是,可能更好的形式是编写一个单独的HideCaret(YourAwesomeTEdit.Handle);
类来实现您想要的顺序,并使用该类的实例。
答案 2 :(得分:6)
如果我理解正确,遵循直截了当的方法应该有效:
Import-Csv .\test.csv | Where-Object {$_.Enabled -eq 'True'} --> what goes here to replace 'True' with 'A'?
它产生:
public class SortArrays {
public static void main(String[] args) {
List<int[]> listOfArrays = new ArrayList<>(4);
listOfArrays.add(new int[]{0, 1, 4, 5});
listOfArrays.add(new int[]{0, 0, 2, 3});
listOfArrays.add(new int[]{0, 1, 1, 2});
Collections.sort(listOfArrays, (o1, o2) -> {
for (int i = 0; i < o1.length; i++) {
if (o1[i] < o2[i])
return -1;
if (o1[i] > o2[i])
return 1;
}
return 0;
});
listOfArrays.forEach(a -> System.out.println(Arrays.toString(a)));
}
}
这就是你所期待的。
答案 3 :(得分:4)
假设您的课程看起来像这样,并且您无法对其进行修改。
final class MyClass
{
private final int[] key;
MyClass(int[] key)
{
this.key = key.clone();
}
public int[] getKey()
{
return key.clone();
}
}
然后,您可以通过实现MyClass
接口为Comparator
的实例定义排序。更一般地说,我实际上要为int[]
实施比较器:
final class IntArrayComparator
implements Comparator<int[]>
{
@Override
public int compare(int[] a, int[] b)
{
int n = Math.min(a.length, b.length);
for (int idx = 0; idx < n; ++idx) {
if (a[idx] != b[idx])
return (a[idx] < b[idx]) ? -1 : +1;
}
return a.length - b.length;
}
}
鉴于这个新的比较器和您现有的类型,它很容易排序:
final class Test
{
public static void main(String... arg)
{
/* Create your list somehow... */
List<MyClass> list = new ArrayList<>();
list.add(new MyClass(new int[]{0, 1, 4, 5}));
list.add(new MyClass(new int[]{0, 0, 2, 3}));
list.add(new MyClass(new int[]{0, 1, 1, 2}));
/* Now sort the list. */
list.sort(Comparator.comparing(MyClass::getKey, new IntArrayComparator()));
/* Display the result... */
list.stream().map(MyClass::getKey).map(Arrays::toString).forEach(System.out::println);
}
}
你应该得到输出:
[0, 0, 2, 3] [0, 1, 1, 2] [0, 1, 4, 5]
我使用的comparing()
工厂方法有两个参数:Function
到&#34;提取&#34;列表中每个对象的键,以及可以比较提取的键的Comparator
。如果提取的密钥具有自然排序,并实现Comparable
(例如,它是String
),那么就没有必要指定Comparator
。< / p>
或者,如果您可以修改MyClass
,则可以通过实施Comparable
并将int[]
比较移至其compareTo()
方法来为其提供自然顺序,如其他答案。然后,您可以使用不带参数的sort()
方法。
答案 4 :(得分:4)
为了对int数组列表进行排序,您需要一个执行int数组的词典比较的函数。这通常表示为Java中的Comparator<int[]>
。实现这种功能的通常方法是从左到右比较相应的值,直到找到不匹配为止;不匹配决定了订单。如果在没有找到不匹配的情况下到达阵列的末尾,则通常认为较短的阵列小于较长的阵列。如果长度相等,并且所有值都相等,则认为数组相等。
其他答案对此函数使用了匿名内部类或lambdas,但对于这样的事情,我更喜欢具有正确&#34;形状&#34;的普通方法,即需要两个int[]
参数并返回int
,这是比较的结果。这使它可以用作方法参考的目标。
int arrayCompare(int[] a, int[] b) {
int len = Math.min(a.length, b.length);
for (int i = 0; i < len; i++) {
int c = Integer.compare(a[i], b[i]);
if (c != 0) {
return c;
}
}
return a.length - b.length;
}
请注意谨慎使用Integer.compare()
而不是减法,以避免潜在的溢出问题。用法如下:
List<int[]> arrays = Arrays.asList(
new int[] { 0, 1, 4, 5 },
new int[] { 0, 0, 2, 3 },
new int[] { 0, 1, 1, 2 }
);
arrays.sort(this::arrayCompare);
arrays.forEach(a -> System.out.println(Arrays.toString(a)));
在JDK 9中,词典数组比较函数已添加到Arrays
类中。见Arrays.compare(int[], int[])
。其他基本类型和引用类型也有重载。 int[]
重载替换了我上面写的arrayCompare
函数,因此您可以按如下方式重写排序调用:
arrays.sort(Arrays::compare);
Arrays
类中比较函数的优点是它们可以由JVM专门处理,例如,它可以使用向量指令来加速数组比较。
针对您的具体问题,您似乎没有int[]
的列表,但是您有一个MyObject
类型的对象列表,其中包含int[]
个你想用作排序键。假设获取数组的方法是调用方法getArray()
。您可以按如下方式对列表进行排序:
myObjects.sort(Comparator.comparing(MyObject::getArray, Arrays::compare));
答案 5 :(得分:2)
考虑这个对象:
public class Foo {
private int[] values;
public Foo(int[] values) {
this.values = values;
}
}
制作对象列表:
ArrayList<Foo> foos = new ArrayList<>();
foos.add(new Foo(new int[] {0, 1, 4, 5}));
foos.add(new Foo(new int[] {0, 0, 2, 3}));
foos.add(new Foo(new int[] {0, 1, 1, 2}));
现在我们要对对象列表进行排序,所以我们要做的第一件事就是使对象实现Comparable
。您应该阅读更多what the Comparable interface is和how to implement it。
public class Foo implements Comparable<Foo> {
...
}
此时,编译器会抱怨您没有实现接口所需的所有方法。那样做。
public class Foo implements Comparable<Foo> {
...
public int compareTo(Foo f) {
// Return a negative integer if this < f
// Return zero if this == f
// Return a positive integer if this > f
}
}
就实际比较逻辑而言,您的问题并不是非常具体地用于比较两个对象的确切规则。但是,从这个例子中,我可以猜测这些是你的规则:
如果一个数组比另一个数组短,那么您没有真正指定要执行的操作。我将把实际的算法留给你(尽管其他答案似乎已经为你做了)。但是,我会指出,因为值是私有字段,除非您为字段实现getter或将其公开,否则您将无法使用该字段进行比较。
public int[] getValues() { return values; }
答案 6 :(得分:2)
如果您的数组是private
并且您确实想要提供一个访问器方法,那么为该类实现Comparable
并执行类似下面的代码。
如果您有访问者方法,请在Comparator
。
此代码does not assume arrays to be of same size
因此适用于不同大小的数组。请根据您的需要进行更改。
PS - 未编译/测试
public int compareTo(Object o) {
CustomClass other = (CustomClass ) o;
int i = 0;
while (i <= numbers.length && i <= other.numbers.length) {
if (numbers[i] < other.numbers[i])
return -1;
else if (numbers[i] > other.numbers[i])
return 1;
++i;
}
if (numbers.length < other.numbers.length)
return -1;
else if (numbers.length > other.numbers.length)
return 1;
return 0;
}