Java 如何通过多个字段比较对象
假设您有一些对象,这些对象具有多个字段,可以通过以下方式进行比较:Java 如何通过多个字段比较对象,java,oop,Java,Oop,假设您有一些对象,这些对象具有多个字段,可以通过以下方式进行比较: public class Person { private String firstName; private String lastName; private String age; /* Constructors */ /* Methods */ } 在本例中,当您询问: a.compareTo(b) > 0 你可能会问a的姓是在b之前,还是a比b大,等等 在不增加不
public class Person {
private String firstName;
private String lastName;
private String age;
/* Constructors */
/* Methods */
}
在本例中,当您询问:
a.compareTo(b) > 0
你可能会问a的姓是在b之前,还是a比b大,等等
在不增加不必要的混乱或开销的情况下,最干净的方法是什么
接口只允许通过一个字段进行比较java.lang.Compariable
- 在我看来,添加大量比较方法(即
,compareByFirstName()
,等等)是杂乱无章的compareByAge()
那么最好的方法是什么呢?我认为如果你的比较算法是“聪明的”,那就更令人困惑了。我赞成你建议的许多比较方法
我唯一的例外是平等。对于单元测试,重写.Equals(在.net中)以确定两个对象之间的几个字段是否相等(而不是引用是否相等)对我来说很有用。您可能希望在Person类中定义几种类型的“Comparator”子类,而不是比较方法。这样,您就可以将它们传递到标准的集合排序方法中。如果用户可以通过多种方式对人员进行排序,您也可以在某个位置将多个s设置为常量。大多数排序操作和排序集合都将比较器作为参数。您可以实现一个比较两个
Person
对象的比较器,并且可以检查任意数量的字段。您可以在比较器中输入一个变量,告诉它要与哪个字段进行比较,尽管只需编写多个比较器可能会更简单。如果您实现该接口,您需要选择一个简单的属性进行排序。这被称为自然排序。将其视为默认设置。它总是在没有提供特定比较器的情况下使用。通常这是一个名称,但您的用例可能需要一些不同的东西。您可以自由地使用任何数量的其他比较器,这些比较器可以提供给各种集合API,以覆盖自然排序
还要注意,通常如果a.compareTo(b)==0,那么a.compareTo(b)==true。如果没有也没关系,但是有副作用需要注意。在Comparable界面上查看优秀的javadocs,您会发现很多关于这方面的信息。您应该实现Comparable
。假设所有字段都不为空(为简单起见),年龄为int,比较排名为first,last,age,则compareTo
方法非常简单:
public int compareTo(Person other) {
int i = firstName.compareTo(other.firstName);
if (i != 0) return i;
i = lastName.compareTo(other.lastName);
if (i != 0) return i;
return Integer.compare(age, other.age);
}
您还可以看看实现Comparator的Enum
e、 g
@Patrick要连续排序多个字段,请尝试
比较器链是按顺序包装一个或多个比较器的比较器。比较器链按顺序调用每个比较器,直到1)任何单个比较器返回非零结果(然后返回该结果),或2)比较器链耗尽(并返回零)。这种排序与SQL中的多列排序非常相似,这个类允许Java类在排序列表时模拟这种行为
为了进一步促进类似SQL的排序,可以颠倒列表中任何单个比较器的顺序
调用添加新比较器或在调用比较(对象,对象)后更改上升/下降排序的方法将导致UnsupportedOperationException。但是,请注意不要更改基础比较器列表或定义排序顺序的位集
ComparatorChain的实例未同步。该类在构造时不是线程安全的,但在所有设置操作完成后执行多重比较是线程安全的
使用起来很容易
e、 g.Objects.equal(姓名2)&&Objects.equal(年龄2)&&……
更多示例:
对于这样的用例,手动编写比较器是一个糟糕的解决方案。这种临时方法有许多缺点:
- 没有代码重用。干的
- 样板
- 增加了出错的可能性
那么解决方案是什么?
首先是一些理论
让我们通过Ord A
来表示命题“typeA
支持比较”。(从程序的角度来看,您可以将Ord A
视为包含用于比较两个A
s的逻辑的对象。是的,就像Comparator
)
现在,如果Ord A
和Ord B
,那么它们的组合(A,B)
也应该支持比较。i、 e.Ord(A,B)
。如果Ord A
、Ord B
和Ord C
,则Ord(A、B、C)
我们可以把这个论点推广到任意算术,并说:
Ord A、Ord B、Ord C、…、Ord Z
⇒ <代码>作战需求文件(A,B,C,…,Z)
让我们把这个语句称为1
复合材料的比较将按照您在问题中所描述的那样进行:首先尝试第一次比较,然后进行下一次比较,然后进行下一次比较,依此类推
这是我们解决方案的第一部分。现在是第二部分
如果您知道Ord A
,并且知道如何将B
转换为A
(调用该转换函数f
),那么您也可以使用Ord B
。怎么用?好的,当比较两个B
实例时,首先使用f
将它们转换为A
,然后应用Ord A
这里,我们正在映射转换B→ A
至作战需求文件A→ 作战需求文件B
。这称为逆变映射(简称comap
)
作战需求文件A,(B)→ A)
⇒comapOrd B
我们来看看卡尔
Collections.sort(myChildren, Child.Order.ByAge.descending());
Ord<Person> personOrd =
p3Ord(stringOrd, stringOrd, stringOrd).comap(
new F<Person, P3<String, String, String>>() {
public P3<String, String, String> f(Person x) {
return p(x.getFirstName(), x.getLastname(), x.getAge());
}
}
);
import com.google.common.collect.ComparisonChain;
/**
* @author radler
* Class Description ...
*/
public class Attribute implements Comparable<Attribute> {
private String type;
private String value;
public String getType() { return type; }
public void setType(String type) { this.type = type; }
public String getValue() { return value; }
public void setValue(String value) { this.value = value; }
@Override
public String toString() {
return "Attribute [type=" + type + ", value=" + value + "]";
}
@Override
public int compareTo(Attribute that) {
return ComparisonChain.start()
.compare(this.type, that.type)
.compare(this.value, that.value)
.result();
}
}
Collections.sort(reportList, Comparator.comparing(Report::getReportKey)
.thenComparing(Report::getStudentNumber)
.thenComparing(Report::getSchool));
Collections.sort(pizzas, new Comparator<Pizza>() {
@Override
public int compare(Pizza p1, Pizza p2) {
int sizeCmp = p1.size.compareTo(p2.size);
if (sizeCmp != 0) {
return sizeCmp;
}
int nrOfToppingsCmp = p1.nrOfToppings.compareTo(p2.nrOfToppings);
if (nrOfToppingsCmp != 0) {
return nrOfToppingsCmp;
}
return p1.name.compareTo(p2.name);
}
});
ComparatorChain chain = new ComparatorChain(Arrays.asList(
new BeanComparator("size"),
new BeanComparator("nrOfToppings"),
new BeanComparator("name")));
Collections.sort(pizzas, chain);
Collections.sort(pizzas, new Comparator<Pizza>() {
@Override
public int compare(Pizza p1, Pizza p2) {
return ComparisonChain.start().compare(p1.size, p2.size).compare(p1.nrOfToppings, p2.nrOfToppings).compare(p1.name, p2.name).result();
// or in case the fields can be null:
/*
return ComparisonChain.start()
.compare(p1.size, p2.size, Ordering.natural().nullsLast())
.compare(p1.nrOfToppings, p2.nrOfToppings, Ordering.natural().nullsLast())
.compare(p1.name, p2.name, Ordering.natural().nullsLast())
.result();
*/
}
});
Collections.sort(pizzas, new Comparator<Pizza>() {
@Override
public int compare(Pizza p1, Pizza p2) {
return new CompareToBuilder().append(p1.size, p2.size).append(p1.nrOfToppings, p2.nrOfToppings).append(p1.name, p2.name).toComparison();
}
});
class MultiComparator<T> implements Comparator<T> {
private final List<Comparator<T>> comparators;
public MultiComparator(List<Comparator<? super T>> comparators) {
this.comparators = comparators;
}
public MultiComparator(Comparator<? super T>... comparators) {
this(Arrays.asList(comparators));
}
public int compare(T o1, T o2) {
for (Comparator<T> c : comparators) {
int result = c.compare(o1, o2);
if (result != 0) {
return result;
}
}
return 0;
}
public static <T> void sort(List<T> list, Comparator<? super T>... comparators) {
Collections.sort(list, new MultiComparator<T>(comparators));
}
}
Collections.sort(list, ComparatorUtils.chainedComparator(comparators));
//here threshold,buyRange,targetPercentage are three keys on that i have sorted my arraylist
final Comparator<BasicDBObject>
sortOrder = new Comparator<BasicDBObject>() {
public int compare(BasicDBObject e1, BasicDBObject e2) {
int threshold = new Double(e1.getDouble("threshold"))
.compareTo(new Double(e2.getDouble("threshold")));
if (threshold != 0)
return threshold;
int buyRange = new Double(e1.getDouble("buyRange"))
.compareTo(new Double(e2.getDouble("buyRange")));
if (buyRange != 0)
return buyRange;
return (new Double(e1.getDouble("targetPercentage")) < new Double(
e2.getDouble("targetPercentage")) ? -1 : (new Double(
e1.getDouble("targetPercentage")) == new Double(
e2.getDouble("targetPercentage")) ? 0 : 1));
}
};
Collections.sort(objectList, sortOrder);
Comparator.comparing((Person p)->p.firstName)
.thenComparing(p->p.lastName)
.thenComparingInt(p->p.age);
Comparator.comparing(Person::getFirstName)
.thenComparing(Person::getLastName)
.thenComparingInt(Person::getAge);
@Override
public int compareTo(Person o){
return Comparator.comparing(Person::getFirstName)
.thenComparing(Person::getLastName)
.thenComparingInt(Person::getAge)
.compare(this, o);
}
import org.apache.commons.lang3.builder.CompareToBuilder;
public int compare(Person a, Person b){
return new CompareToBuilder()
.append(a.getName(), b.getName())
.append(a.getAddress(), b.getAddress())
.toComparison();
}
.ThenBy(...)
.thenComparing(...)
Comparator<Person> comparator = Comparator.comparing(person -> person.name);
comparator = comparator.thenComparing(Comparator.comparing(person -> person.age));
@Test
public void testChainedSorting()
{
// Create the collection of people:
ArrayList<Person> people = new ArrayList<>();
people.add(new Person("Dan", 4));
people.add(new Person("Andi", 2));
people.add(new Person("Bob", 42));
people.add(new Person("Debby", 3));
people.add(new Person("Bob", 72));
people.add(new Person("Barry", 20));
people.add(new Person("Cathy", 40));
people.add(new Person("Bob", 40));
people.add(new Person("Barry", 50));
// Define chained comparators:
// Great article explaining this and how to make it even neater:
// http://blog.jooq.org/2014/01/31/java-8-friday-goodies-lambdas-and-sorting/
Comparator<Person> comparator = Comparator.comparing(person -> person.name);
comparator = comparator.thenComparing(Comparator.comparing(person -> person.age));
// Sort the stream:
Stream<Person> personStream = people.stream().sorted(comparator);
// Make sure that the output is as expected:
List<Person> sortedPeople = personStream.collect(Collectors.toList());
Assert.assertEquals("Andi", sortedPeople.get(0).name); Assert.assertEquals(2, sortedPeople.get(0).age);
Assert.assertEquals("Barry", sortedPeople.get(1).name); Assert.assertEquals(20, sortedPeople.get(1).age);
Assert.assertEquals("Barry", sortedPeople.get(2).name); Assert.assertEquals(50, sortedPeople.get(2).age);
Assert.assertEquals("Bob", sortedPeople.get(3).name); Assert.assertEquals(40, sortedPeople.get(3).age);
Assert.assertEquals("Bob", sortedPeople.get(4).name); Assert.assertEquals(42, sortedPeople.get(4).age);
Assert.assertEquals("Bob", sortedPeople.get(5).name); Assert.assertEquals(72, sortedPeople.get(5).age);
Assert.assertEquals("Cathy", sortedPeople.get(6).name); Assert.assertEquals(40, sortedPeople.get(6).age);
Assert.assertEquals("Dan", sortedPeople.get(7).name); Assert.assertEquals(4, sortedPeople.get(7).age);
Assert.assertEquals("Debby", sortedPeople.get(8).name); Assert.assertEquals(3, sortedPeople.get(8).age);
// Andi : 2
// Barry : 20
// Barry : 50
// Bob : 40
// Bob : 42
// Bob : 72
// Cathy : 40
// Dan : 4
// Debby : 3
}
/**
* A person in our system.
*/
public static class Person
{
/**
* Creates a new person.
* @param name The name of the person.
* @param age The age of the person.
*/
public Person(String name, int age)
{
this.age = age;
this.name = name;
}
/**
* The name of the person.
*/
public String name;
/**
* The age of the person.
*/
public int age;
@Override
public String toString()
{
if (name == null) return super.toString();
else return String.format("%s : %d", this.name, this.age);
}
}
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
/**
* This is a chained comparator that is used to sort a list by multiple
* attributes by chaining a sequence of comparators of individual fields
* together.
*
*/
public class EmployeeChainedComparator implements Comparator<Employee> {
private List<Comparator<Employee>> listComparators;
@SafeVarargs
public EmployeeChainedComparator(Comparator<Employee>... comparators) {
this.listComparators = Arrays.asList(comparators);
}
@Override
public int compare(Employee emp1, Employee emp2) {
for (Comparator<Employee> comparator : listComparators) {
int result = comparator.compare(emp1, emp2);
if (result != 0) {
return result;
}
}
return 0;
}
}
Collections.sort(listEmployees, new EmployeeChainedComparator(
new EmployeeJobTitleComparator(),
new EmployeeAgeComparator(),
new EmployeeSalaryComparator())
);
public int compareTo(Person other) {
int f = firstName.compareTo(other.firstName);
int l = lastName.compareTo(other.lastName);
return f != 0 ? f : l != 0 ? l : Integer.compare(age, other.age);
}
public class Sample{
String a=null;
String b=null;
public Sample(){
a="s";
b="a";
}
public Sample(String a,String b){
this.a=a;
this.b=b;
}
public static void main(String args[]){
Sample f=new Sample("b","12");
Sample s=new Sample("b","12");
//will return true
System.out.println((s.a.hashCode()+s.b.hashCode())==(f.a.hashCode()+f.b.hashCode()));
//will return false
Sample f=new Sample("b","12");
Sample s=new Sample("b","13");
System.out.println((s.a.hashCode()+s.b.hashCode())==(f.a.hashCode()+f.b.hashCode()));
}
//Following is the example in jdk 1.8
package com;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
class User {
private String firstName;
private String lastName;
private Integer age;
public Integer getAge() {
return age;
}
public User setAge(Integer age) {
this.age = age;
return this;
}
public String getFirstName() {
return firstName;
}
public User setFirstName(String firstName) {
this.firstName = firstName;
return this;
}
public String getLastName() {
return lastName;
}
public User setLastName(String lastName) {
this.lastName = lastName;
return this;
}
}
public class MultiFieldsComparision {
public static void main(String[] args) {
List<User> users = new ArrayList<User>();
User u1 = new User().setFirstName("Pawan").setLastName("Singh").setAge(38);
User u2 = new User().setFirstName("Pawan").setLastName("Payal").setAge(37);
User u3 = new User().setFirstName("Anuj").setLastName("Kumar").setAge(60);
User u4 = new User().setFirstName("Anuj").setLastName("Kumar").setAge(43);
User u5 = new User().setFirstName("Pawan").setLastName("Chamoli").setAge(44);
User u6 = new User().setFirstName("Pawan").setLastName("Singh").setAge(5);
users.add(u1);
users.add(u2);
users.add(u3);
users.add(u4);
users.add(u5);
users.add(u6);
System.out.println("****** Before Sorting ******");
users.forEach(user -> {
System.out.println(user.getFirstName() + " , " + user.getLastName() + " , " + user.getAge());
});
System.out.println("****** Aftre Sorting ******");
users.sort(
Comparator.comparing(User::getFirstName).thenComparing(User::getLastName).thenComparing(User::getAge));
users.forEach(user -> {
System.out.println(user.getFirstName() + " , " + user.getLastName() + " , " + user.getAge());
});
}
}
public int compareTo(Song o) {
// TODO Auto-generated method stub
int comp1 = 10000000*(movie.compareTo(o.movie))+1000*(artist.compareTo(o.artist))+songLength;
int comp2 = 10000000*(o.movie.compareTo(movie))+1000*(o.artist.compareTo(artist))+o.songLength;
return comp1-comp2;
}
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
public class Person {
private String firstName;
private String lastName;
private int age;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Person(String firstName, String lastName, int age) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
}
static class PersonSortingComparator implements Comparator<Person> {
@Override
public int compare(Person person1, Person person2) {
// for first name comparison
int firstNameCompare = person1.getFirstName().compareTo(person2.getFirstName());
// for last name comparison
int lastNameCompare = person1.getLastName().compareTo(person2.getLastName());
// for last name comparison
int ageCompare = person1.getAge() - person2.getAge();
// Now comparing
if (firstNameCompare == 0) {
if (lastNameCompare == 0) {
return ageCompare;
}
return lastNameCompare;
}
return firstNameCompare;
}
}
public static void main(String[] args) {
Person person1 = new Person("Ajay", "Kumar", 27);
Person person2 = new Person("Ajay","Gupta", 23);
Person person3 = new Person("Ajay","Kumar", 22);
ArrayList<Person> persons = new ArrayList<>();
persons.add(person1);
persons.add(person2);
persons.add(person3);
System.out.println("Before Sorting:\n");
for (Person person : persons) {
System.out.println(person.firstName + " " + person.lastName + " " + person.age);
}
Collections.sort(persons, new PersonSortingComparator());
System.out.println("After Sorting:\n");
for (Person person : persons) {
System.out.println(person.firstName + " " + person.lastName + " " + person.age);
}
}
}
public class MyData {
int id;
boolean relevant;
String name;
float value;
}
public class MultiFieldComparator implements Comparator<MyData> {
@Override
public int compare(MyData dataA, MyData dataB) {
int result;
if((result = Integer.compare(dataA.id, dataB.id)) == 0 &&
(result = Boolean.compare(dataA.relevant, dataB.relevant)) == 0 &&
(result = dataA.name.compareTo(dataB.name)) == 0)
result = Float.compare(dataA.value, dataB.value);
return result;
}
}
myDataList.sort((dataA, dataB) -> {
int result;
if((result = Integer.compare(dataA.id, dataB.id)) == 0 &&
(result = Boolean.compare(dataA.relevant, dataB.relevant)) == 0 &&
(result = dataA.name.compareTo(dataB.name)) == 0)
result = Float.compare(dataA.value, dataB.value);
return result;
});