为什么我的 TreeSet 没有在第一个元素之外添加任何内容? [英] Why does my TreeSet not add anything beyond the first element?

查看:22
本文介绍了为什么我的 TreeSet 没有在第一个元素之外添加任何内容?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有几个数组的形式:

private static String[] patientNames = { "John Lennon", "Paul McCartney", "George Harrison", "Ringo Starr" };

然后我制作一个这样的 TreeSet:

TreeSetpatTreeSet = new TreeSet<患者>();

其中 Patient 是制作Patient"对象的不同类.然后我循环遍历数组中的每个元素以创建几个患者并将它们添加到我的 patTreeSet 中,如下所示:

for(int i = 0; i

但是当我去检查我的 patTreeSet.size() 时,它只返回1" - 这是为什么?

我知道我的对象运行良好,因为当我尝试做同样的事情但使用 ArrayList 时,一切正常.所以我猜我用错了 TreeSet.

如果有帮助,Patient 有一个名为 getFirstName() 的方法,当我尝试执行以下操作时:

迭代器patItr = patTreeSet.iterator();而(patItr.hasNext()){System.out.println(patItr.next().getFirstName());}

然后只有John"打印,显然不应该是这种情况......那么,我完全误用了 TreeSet 吗?

提前感谢您的帮助!

编辑下面

================PatientImpl 类====================

public class PatientImpl 实现 Patient, Comparable{日历 cal = new GregorianCalendar();私人字符串名;私人字符串姓氏;私有字符串 SSN;私人日期出生日期;私人年龄;私人 int thisID;公共静态int ID = 0;公共 PatientImpl(字符串全名,字符串 SSN,日期 dob){String[] name = fullName.split(" ");名字 = 名字[0];姓氏 = 名称[1];这个.SSN = SSN;这个.dob = dob;这个ID = ID += 1;}@覆盖公共布尔等于(对象 p){//出于某种原因,在此处进行强制转换并重新分配 p 的值并不能满足在 if 语句中进行强制转换的需要...p = (PatientImpl) p;布尔等于 = 假;//在我们比较任何东西之前确保p是一个病人if (p instanceof Patient) {患者温度=(患者)p;if (this.firstName.equalsIgnoreCase(temp.getFirstName())) {if (this.lastName.equalsIgnoreCase(temp.getLastName())) {if (this.SSN.equalsIgnoreCase(temp.getSSN())) {if(this.dob.toString().equalsIgnoreCase(((PatientImpl) p).getDOB().toString())){if(this.getID() == temp.getID()){等于=真;}}}}}}返回相等;}

然后所有的getter都在下面,还有Comparable接口的compareTo()方法

解决方案

如果您将对象放在 TreeSet 中,则需要提供 Comparator 的实现构造函数中的接口,或者您需要您的对象属于实现 Comparable 的类.

您说您从 Comparable 接口实现 compareTo ,但在您的评论中您说您没有,所以我假设您只是 return 0;compareTo 方法中?这可以解释你的问题,因为 TreeSet 会根据 compareTo 方法的结果认为你所有的对象都是相同的".

基本上,在 TreeSet 中,您的对象按排序顺序维护,排序由 Comparable/Comparator 方法的结果决定.这用于在 TreeSet 中快速查找重复项,并具有额外的好处,即当您遍历 TreeSet 时,您可以按排序顺序获得结果.

TreeSet 的 Javadoc 说:

<块引用>

请注意,由集合维护的顺序(无论是否显式提供了比较器)必须与equals一致如果它是正确实现Set接口.

实现这一点的最简单方法是让您的 equals 方法调用 compareTo 方法并检查结果是否为 0.

鉴于您的 PatientImpl 类,我假设您希望先按姓氏对患者进行排序,然后按名字对患者进行排序,然后再按类中的其余字段排序.p>

您可以像这样实现 compareTo 方法:

@Override公共 int compareTo(对象 o){if (!(o instanceof Patient))返回-1;患者温度=(患者)o;int r = this.lastName.compareToIgnoreCase(temp.getLastName());如果(r == 0)r = this.firstName.compareToIgnoreCase(temp.getFirstName());如果(r == 0)r = this.SSN.compareToIgnoreCase(temp.getSSN());如果(r == 0)r = this.dob.toString().compareToIgnoreCase(temp.getDOB().toString());如果(r == 0)r = Integer.compare(this.getID(), temp.getID());返回 r;}

我相信这会解决您描述的问题.我建议您阅读(Javadoc 或书籍)关于 TreeSetHashSet 以及 equalscompareTohashCode 方法.如果您想将您的对象放入 Set 或 Map 中,您需要了解这些才能正确实现.

注意我将此 compareTo 方法基于您的 equals 方法.您通过首先调用 toString 来比较出生日期.这不是一个很好的方法——您可以直接在 java.util.Date 中使用 equals 方法.在 compareTo 方法中,问题变得更糟,因为当您按字母顺序对日期进行排序时,日期排序不正确.java.util.Date 还实现了 Comparable,因此您可以将方法中的比较替换为:

 if (r == 0)r = this.dob.compareTo(temp.getDOB());

此外,如果任何字段可能为 null,您也需要检查.

I have several arrays in the form:

private static String[] patientNames = { "John Lennon", "Paul McCartney", "George Harrison", "Ringo Starr" };

Then I make a TreeSet like this:

TreeSet<Patient> patTreeSet = new TreeSet<Patient>();

Where Patient is a different class that makes "Patient" objects. Then I loop through each element in my arrays to create several patients and add them to my patTreeSet like this:

for(int i = 0; i< patientNames.length; i++){
     Date dob = date.getDate("MM/dd/yyyy", patientBirthDates[i]);
     Patient p = new PatientImpl(patientNames[i], patientSSN[i], dob);

     patTreeSet.add(p);
}

But when I go to check my patTreeSet.size() it only returns "1" - why is this?

I know my objects are working well because when I try to do the same thing but with ArrayList instead, everything works fine. So I'm guessing I'm using the TreeSet wrong.

If it helps, Patient has a method called getFirstName(), and when I try to do the following:

Iterator<Patient> patItr = patTreeSet.iterator();

while(patItr.hasNext()){
    System.out.println(patItr.next().getFirstName());

}

Then only "John" prints, which obviously shouldn't be the case... So, am I totally misusing the TreeSet?

Thanks in advance for any help!

EDIT below

================PatientImpl Class====================

public class PatientImpl implements Patient, Comparable{

    Calendar cal = new GregorianCalendar();
    private String firstName;
    private String lastName;
    private String SSN;
    private Date dob;
    private int age;
    private int thisID;             
    public static int ID = 0;       



    public PatientImpl(String fullName, String SSN, Date dob){

        String[] name = fullName.split(" ");
        firstName = name[0];
        lastName = name[1];

        this.SSN = SSN;

        this.dob = dob;

        thisID = ID += 1;
    }

@Override
    public boolean equals(Object p) {

        //for some reason casting here and reassigning the value of p doesn't take care of the need to cast in the if statement...
        p = (PatientImpl) p;

        Boolean equal = false;
        //make sure p is a patient before we even compare anything
        if (p instanceof Patient) {

            Patient temp = (Patient) p;

            if (this.firstName.equalsIgnoreCase(temp.getFirstName())) {
                if (this.lastName.equalsIgnoreCase(temp.getLastName())) {
                    if (this.SSN.equalsIgnoreCase(temp.getSSN())) {
                        if(this.dob.toString().equalsIgnoreCase(((PatientImpl) p).getDOB().toString())){
                            if(this.getID() == temp.getID()){
                                equal = true;
                            }
                        }
                    }
                }
            }
         }
        return equal;
    }

and then all the getters are below, as well as the compareTo() method from the Comparable interface

解决方案

If you put your objects in a TreeSet, you need to either provide an implementation of the Comparator interface in the constructor, or you need your objects to be of a class that implements Comparable.

You said you implement compareTo from the Comparable interface, but in your comment you say that you didn't, so am I correct in assuming that you just return 0; in the compareTo method? That would explain your problem, because TreeSet would then think that all your objects are 'the same' based on the compareTo method result.

Basically, in a TreeSet, your objects are maintained in a sorted order, and the sorting is determined by the outcome of the Comparable/Comparator method. This is used to quickly find duplicates in a TreeSet and has the added benefit that when you iterate over the TreeSet, you get the results in sorted order.

The Javadoc of TreeSet says:

Note that the ordering maintained by a set (whether or not an explicit comparator is provided) must be consistent with equals if it is to correctly implement the Set interface.

The easiest way to achieve that is to let your equals method call the compareTo method and check if the result is 0.

Given your PatientImpl class, I assume that you would want to sort patients first by their last name, then by their first name, and then by the rest of the fields in the class.

You could implement a compareTo method like this:

@Override
public int compareTo(Object o) {
    if (!(o instanceof Patient))
        return -1;
    Patient temp = (Patient) o;
    int r = this.lastName.compareToIgnoreCase(temp.getLastName());
    if (r == 0)
        r = this.firstName.compareToIgnoreCase(temp.getFirstName());
    if (r == 0)
        r = this.SSN.compareToIgnoreCase(temp.getSSN());
    if (r == 0)
        r = this.dob.toString().compareToIgnoreCase(temp.getDOB().toString());
    if (r == 0)
        r = Integer.compare(this.getID(), temp.getID());
    return r;
}

I believe that would solve the problem you described. I would advise you to read up (Javadoc or books) on TreeSet and HashSet and the importance of the equals, compareTo and hashCode methods. If you want to put your objects in a Set or a Map, you need to know about these to implement that correctly.

Note I based this compareTo method on your equals method. You were comparing the date-of-birth by first calling toString. That's not a very good way of doing that - you can use the equals method in java.util.Date directly. In a compareTo method the problem gets worse because dates do not sort correctly when you sort them alphabetically. java.util.Date also implements Comparable so you can replace that comparison in the method with:

    if (r == 0)
        r = this.dob.compareTo(temp.getDOB());

In addition, if any of the fields could be null, you need to check for that as well.

这篇关于为什么我的 TreeSet 没有在第一个元素之外添加任何内容?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆