简体   繁体   English

不同类对象的相同排序算法(Java)

[英]Same sorting algorithm for objects of different classes (Java)

Right now I have a sorting algorithm that takes an array of objects in random order, sorts them into a new array based on a value attribute and returns the sorted array (Specifically an ArrayList altough I don't belive it will be relevant for my question).现在我有一个排序算法,它以随机顺序获取一个对象数组,根据值属性将它们排序到一个新数组中并返回排序后的数组(特别是 ArrayList 虽然我不相信它会与我的问题相关)。 For my assignment I have now been instructed to sort another array of different objects, from order of highest to lowest based on these different objects' own value attributes.对于我的任务,我现在被指示根据这些不同对象自己的值属性从最高到最低的顺序对另一个不同对象的数组进行排序。 Instead of copypasting my already implemented algorithm altough changing object and attribute name in a couple of places or just straight up sorting the other objects in O(n^2) order, I would like to somehow reuse my current algorithm in a more general manner.我不想复制粘贴我已经实现的算法,尽管在几个地方更改 object 和属性名称,或者只是直接按 O(n^2) 顺序对其他对象进行排序,我想以更通用的方式重用我当前的算法。 To be more clear:为了更清楚:

new Array<ClassA> a;
new Array<ClassB> b;

public Array<ClassB> sort(Array<ClassB> input){
    //sort based on certain attribute in ClassB;
    return sortedArray;
}

I wish to turn into:我想变成:

new Array<ClassA> a;
new Array<ClassB> b;

public Array<ClassB> sort(Array<Object> input, Attribute x){
    //sort based on attribute of Object where which attribute is given as a parameter x;
    return sortedArray;
}

I understand this might come of as even more confusing than my written explanation so to be even MORE clear (I hope) I wish to turn my sorting algorithm into something simillar to this built in function from python: sorted(iterable, key=None, reverse=False)我知道这可能比我的书面解释更令人困惑,所以更清楚(我希望)我希望将我的排序算法变成类似于 python 中的 function 内置的排序算法:sorted(iterable, key=None,反向=假)

The algorithm I have implemented is part of the assignment so I can't replace it with something from a library.我实现的算法是作业的一部分,所以我不能用库中的东西替换它。 If you thought my entire question was dumb, then please consider that english is not my native language, no - I am not quite familiar at all with programming terminology and yes - I am quite a terrible programmer.如果您认为我的整个问题很愚蠢,那么请考虑一下英语不是我的母语,不-我对编程术语一点也不熟悉,是的-我是一个非常糟糕的程序员。 Then move on with your day, If you think you can provide me a reasonable answer however: it would be much appreciated :D然后继续你的一天,如果你认为你可以给我一个合理的答案:我将不胜感激:D

public Array<ClassB> sort(Array<Object> input, Attribute x){

this turns an array of arbitrary objects into an array containing instances of ClassB , which obviously insn't how it works.这会将任意对象数组转换为包含ClassB实例的数组,这显然不是它的工作原理。

Array<Object> input

This doesn't mean what you think it means.这并不意味着你认为它意味着什么。 An Array<ClassB> is NOT a valid value for Array<Object> . Array<ClassB>不是Array<Object>的有效值。 After all, I can add a String to an Array<Object> (a String is an object,), but I can't add one to an Array<ClassB> .毕竟,我可以将字符串添加到Array<Object> (字符串是 object,),但我不能将字符串添加到Array<ClassB> In computer tech terms, basic types in java (like Number and Integer ) are covariant - any instance that is a subtype of X is also an X: An Integer is also a Number, is also an Object. In computer tech terms, basic types in java (like Number and Integer ) are covariant - any instance that is a subtype of X is also an X: An Integer is also a Number, is also an Object. But type args are invariant .但是类型 args 是不变的。 Any instance that is a subtype of X, isn't compatible with X: a List<Integer> is not a List<Number> .任何属于 X 子类型的实例都与 X 不兼容: List<Integer>不是List<Number> This is because that's just how it works, as I showed above: You can add doubles to a List<Number> .这是因为这就是它的工作原理,正如我在上面展示的:您可以将双打添加到List<Number>

You can pick different variances: List<? extends Number>您可以选择不同的差异: List<? extends Number> List<? extends Number> or List<? super Number> List<? extends Number>List<? super Number> List<? super Number> do this. List<? super Number>这样做。 You don't need it for this problem, though.不过,您不需要它来解决这个问题。

Generics link things. Generics 链接东西。 That's what you want here: Take in an array of some.. thing, and return an array of the same thing:这就是你想要的:接受一些..事物的数组,并返回相同事物的数组:

public <T> Array<T> sort(Array<T> input, Attribute x) {}

This says: There is some type T .这说:有一些类型T No idea what it is.不知道它是什么。 This T then serves to link things: Whatever the type of the input array?然后这个 T 用于链接事物:无论输入数组的类型是什么? the output array has the same type. output 阵列具有相同的类型。

Which is what you want.这就是你想要的。

Attribute x

It is not possible to refer to attributes in a programmatic manner.无法以编程方式引用属性。 Fortunately, you don't actually need an attribute.幸运的是,您实际上并不需要属性。 You need a function: Given some T , provide a value;你需要一个 function:给定一些T ,提供一个值; one that you now how to sort inherently.一个,你现在如何固有地排序。 How this function works?这个 function 是如何工作的? You don't care.你不在乎。 Long as it is consistent (returns the same value for any given instance), you can then sort it all based on that mapped value.只要它是一致的(为任何给定实例返回相同的值),您就可以根据该映射值对其进行排序。 So, you don't want Attribute , you want a function that turns a T into some thing you can sort.所以,你不想要Attribute ,你想要一个 function 把一个 T 变成你可以排序的东西。 You have three options:你有三个选择:

Go on a spree, listing every sortable concept you have. Go 大吃一惊,列出您拥有的每个可分类概念。

public <T> Array<T> sortByInt(Array<T> input, ToIntFunction<T> f) {}
public <T> Array<T> sortByString(Array<T> input, Function<T, String> f) {}
public <T> Array<T> sortByDouble(Array<T> input, ToDoubleFunction<T, String> f) {}

etcetera.等等。 These methods really need different names, you don't want overloading here.这些方法确实需要不同的名称,你不想在这里重载。

Map to object and pray Map 到 object 并祈祷

You have no idea how to sort any given object.您不知道如何对任何给定的 object 进行排序。 You presumably only know how to sort integer, double, and string.你想必只知道 integer、double 和 string 的排序方式。 You could write:你可以写:

public <T> Array<T> sortByDouble(Array<T> input, Function<T, ?> f) {}

and then do checks at runtime if the function maps to what you wanted.然后在运行时检查 function 是否映射到您想要的。 If the function maps to, say, an InputStream , which is obviously not a thing you can sort, you'd have to check it, and throw an exception.如果 function 映射到一个InputStream ,这显然不是你可以排序的东西,你必须检查它,然后抛出一个异常。 It also gets quite confusing if one object is mapped to an int and another to a string.如果一个 object 映射到一个 int 而另一个映射到一个字符串,它也会变得相当混乱。 This sounds simple, but it isn't.这听起来很简单,但事实并非如此。 Do not do this.不要这样做。

Use java' built in concept of self-ordered stuff.使用 java' 内置的自订购东西的概念。

Java has a type for this: Comparable . Java 有一个类型: Comparable This gets a little complex;这有点复杂。 you want, here, that the objects can compare themselves to themselves, so:在这里,您希望对象可以将自己与自己进行比较,因此:

public <T, V extends Comparable<V>> Array<T> sort(Array<T> input, Function<T, V> f) {}

That is getting a little complex, but it is the most correct version.这有点复杂,但它是最正确的版本。 Let's go through it:让我们通过它 go :

  • The <T, V... > part: This says that this method has 2 type variables. <T, V... >部分:这表示此方法有 2 个类型变量。 They are like normal variables, except they hold types.它们就像普通变量一样,除了它们持有类型。
  • The T : It has no bounds whatsoever. T :它没有任何界限。 Thus, it can be anything.因此,它可以是任何东西。 Any code that calls this method will either explicitly pick something, or the compiler will figure it out.任何调用此方法的代码都将显式选择某些内容,或者编译器会找出答案。
  • The V : This has bounds. V :这是有界限的。 V cannot just be anything. V 不能只是任何东西。 V must be some type that has the property that it implements Comparable<V> - in other words, a thing that can compare itself to another value of its own type. V 必须是具有实现Comparable<V>的属性的某种类型 - 换句话说,一种可以将自身与其自身类型的另一个值进行比较的事物。 String , Integer , and many other things built into java are like this. StringInteger和 java 内置的许多其他东西都是这样的。 String is a valid type to fill in for V . String是填写V的有效类型。
  • Array<T> - what the method returns. Array<T> - 方法返回的内容。
  • sort - the method name sort - 方法名
  • Array<T> input - the input. Array<T> input - 输入。 Note that this is linked to the return type.请注意,这与返回类型相关联。
  • Function<T, V> - a function. Function<T, V> - 一个 function。 This function will take in an object of type T and returns an object of type V. Remember, V can't just be anything - it needs to be some specific type that can order itself vs. something else of the same type, such as String or Integer .这个 function 将接受 T 类型的 object 并返回 V 类型的 object。记住,V 不能只是任何东西 - 它需要是某种特定类型,例如可以订购自己StringInteger

With all this, you can write some code.有了这一切,您可以编写一些代码。 For example:例如:

T first = input.get(0); // still no idea what T is. But `input.get(0)` returns it.
T second = input.get(1);
V firstAttribute = function.apply(first); // extracts the sortable attribute
V secondAttribute = function.apply(second);
int ordering = firstAttribute.compareTo(secondAttribute); // magic!

That last line is a marvel.最后一行是一个奇迹。 It compiles, and is guaranteed to work: firstAttribute is a V , and whilst we have no idea what V is (could be String. Could also be Integer), we do know that V has the int compareTo(V other) method.它可以编译,并保证可以工作: firstAttribute 是V ,虽然我们不知道 V 是什么(可能是字符串。也可能是整数),但我们知道 V 有int compareTo(V other)方法。 So, we can invoke that.所以,我们可以调用它。 A negative number means first is before second , a positive means first is after second, and a 0 response means first and second are either equal or, as far as comparing them is concerned, siblings - neither is 'before' the other.负数表示firstsecond之前,正数表示first在 second 之后,而0响应表示firstsecond相等,或者就比较它们而言,兄弟姐妹 - 两者都不是“之前”。

That function is all you need to write sort algorithms. function 是编写排序算法所需的全部内容。

Note ethat, given that first is a T , you can write:请注意,鉴于firstT ,您可以编写:

Array<T> output = new Array<T>();
output.add(first);

The compiler does not know what T is, but it does know that first is a T, so this call is allowed.编译器不知道T是什么,但它知道first是一个 T,所以允许这个调用。

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

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