简体   繁体   English

对对象有多种类型的排序

[英]Having multiple types of sorts for an object

Lets say that I have an java object with multiple String fields. 假设我有一个带有多个String字段的java对象。

public class Person {
    private String field1
    // keeps going 

I want to be able to have the ability to sort a list of persons depending on whatever field I choose. 我希望能够根据我选择的任何领域对人员列表进行排序。

I know that I can use the comparator interface and implement multiple compareTo's as described in the topic: How do I make 2 comparable methods in only one class? 我知道我可以使用比较器接口并实现多个compareTo,如主题所述: 如何在一个类中制作2个可比较的方法?

But while using Collections.sort() 但是在使用Collections.sort()

But is there some way for me to do this without all this repeating code? 但是,如果没有所有这些重复代码,我有什么方法可以做到这一点吗?

If you don't like the verbosity of Comparator classes, then use Java 8 and its lambda expressions: 如果您不喜欢Comparator类的详细程度,那么使用Java 8及其lambda表达式:

Comparator<Person> byName = Comparator.comparing(Person::getName);
Comparator<Person> byBirthDate = Comparator.comparing(Person::getBirthDate);

I want to be able to have the ability to sort a list of persons depending on whatever field I choose. 我希望能够根据我选择的任何领域对人员列表进行排序。

@JB Nizet's solution for Java 8 will make a trick but it works only from Java 8. What about version(s) lower than 8 which are used by majority of people? @JB Nizet的 Java 8解决方案将成为一个技巧,但它仅适用于Java 8.大多数人使用的低于8的版本是什么?

I will provide you i think simple solution for lower versions than Java 8. 我将为您提供我认为比Java 8更低版本的简单解决方案。

You really don't need to create more than one Comparator class (you mentioned it as "repeating code"). 您真的不需要创建多个Comparator类(您将其称为“重复代码”)。 What about to use proper techniques like if conditions or enums? 如何使用适当的技术,如条件或枚举?

private Comparator<YourClass> getComparator(MyPropertiesEnum myEnum) {
   return new Comparator<YourClass>() {

      @Override
      public int compare(YourClass o1, YourClass o2) { {
         switch (myEnum) {
            case FIRSTNAME:
               // implementation for firstname
            break;
            case LASTNAME:
              // implementation for lastname
            break;
            default:
               // implementation for default version
            break;           
         }
      }
   };
}

Where MyPropertiesEnum can looks like: MyPropertiesEnum如下:

public enum MyPropertiesEnum {
   FIRSTNAME, LASTNAME, AGE;
}

Note: Also you can use proper if conditions if they are more comfortable for you. 注意:如果条件适合您,也可以使用适当的条件。

Hope it'll help you solve your issue. 希望它能帮助您解决问题。

public class Person {
    private String field1;
    private String field2;
    ...
    private Map<String,String> allFields;

    ...
    public void setField1 (String value) {
        field1 = value;
        allFields.put("field1",value);
    }

    public void setField2 (String value) {
        field2 = value;
        allFields.put("field2",value);
    }

Or whatever names you want. 或者你想要的任何名字。 Or you can use an enum instead of a String as the map key. 或者您可以使用enum而不是String作为地图键。 This demonstrates why using getters and setters is a good idea, by the way; 这说明为什么顺便说一句,使用getter和setter是一个好主意; you couldn't do this by using public member fields and letting clients assign to them directly. 你不能通过使用公共成员字段并让客户直接分配给他们来做到这一点。 But since you make the fields private and require a setter to set them, you can ensure that the String field and the map entry always match. 但由于您将字段设为private并需要setter来设置它们,因此可以确保String字段和映射条目始终匹配。

Now it should be easy to write a single Comparator that looks for the desired field by looking it up in allFields . 现在,编写一个通过在allFields查找所需字段的Comparator应该很容易。

This is an sketch of a generic approach. 这是一种通用方法的草图。

It should work as long as the types of the fields implement the compareTo method (that is, you should use Integer vs int and so on) 它应该工作只要字段的类型实现compareTo方法(也就是说,你应该使用Integer vs int等)

DISCLAIMER : I have not taken into account any performance issues :) 免责声明 :我没有考虑任何性能问题:)

Sorter.java Sorter.java

package sovflow;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Sorter<ObjectType, FieldType extends Comparable<FieldType>> {

    public List<Wrapper<ObjectType, FieldType>> sort(List<ObjectType> list,
            Field field) {
        field.setAccessible(true);
        List<Wrapper<ObjectType, FieldType>> _list = new ArrayList<Wrapper<ObjectType, FieldType>>();
        for (ObjectType object : list) {
            Wrapper<ObjectType, FieldType> wrapper = new Wrapper<ObjectType, FieldType>(
                    field, object);
            _list.add(wrapper);
        }
        Collections.sort(_list);
        return _list;
    }

}

Wrapper.java Wrapper.java

package sovflow;

import java.lang.reflect.Field;

public class Wrapper<ObjectType, FieldType extends Comparable<FieldType>>
        implements Comparable<Wrapper<ObjectType, FieldType>> {

    Field field;
    ObjectType object;

    public Wrapper(Field field, ObjectType object) {
        this.field = field;
        this.object = object;
    }

    @SuppressWarnings("unchecked") // for the field.get. Unavoidable, i'd say :)
    public int compareTo(Wrapper<ObjectType, FieldType> paramT) {
        try {   
            return ((FieldType) field.get(object)).compareTo((FieldType)field.get(paramT.object));
        } catch (Exception e) {
            e.printStackTrace();
        } 
        return 0;
    }

    public void print() {
        System.out.println(object);

    }

}

This is an example of how to use it: 这是如何使用它的示例:

package sovflow;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

public class Main {
    private static class Person {

        private Integer id;
        private String name;
        public Person(Integer id, String name) {
            super();
            this.id = id;
            this.name = name;
        }
        @Override
        public String toString() {
            return "Id = " + id + " name = " + name;
        }       
    }

    public static void main(String[] args) {
        Person p = new Person(1, "B");
        Person p2 = new Person(2, "A");
        List<Person> list = new ArrayList<Person>();
        list.add(p);
        list.add(p2);
        Sorter<Person, String> sorter = new Sorter<Person, String>();
        try {
            Field declaredField = Person.class.getDeclaredField("name");
            // Just to show the result. The sort method could be modified to
            // not having to deal with the wrapper here..
            List<Wrapper<Person,String>> list2 = sorter.sort(list, declaredField);          
            for (Wrapper<Person, String> wrapper : list2) {
                wrapper.print();
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
}

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

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