【问题标题】:Iterator stops midway through after finding a match迭代器在找到匹配后中途停止
【发布时间】:2015-11-16 21:31:55
【问题描述】:
//Example from class that I was trying to base off of:

public void printMajors(String major) {
for(Student x : dir) {

//dir = new HashMap<Integer, Student>(); and Student is the second class.

if (x.getMajor().equals(major)) {
System.out.println(x.getName());
    }
}

}

我想打印出所有插入了相同区号但迭代器在找到匹配项后中途停止的人。如何让它继续循环并打印出具有相同区号的每个人?

//代码中的问题

public boolean printAreaCode(String areacode) {
    for (String p : phonebook.values()) {
        if (p.startsWith(areacode)) {
            for (String name : phonebook.keySet()) {
                String key = name;
                System.out.println(key);
                return true;
            }
        }
    }
    return false;
}

整个作业

import java.util.HashMap;
import java.util.Iterator;

public class PhoneBook {

    private HashMap<String, String> phonebook;

    public static void main(String[] args) {
    PhoneBook phone = new PhoneBook();
    phone.addEntry("Alexander Schnell", "987-654-3210");
    phone.addEntry("Bob the Builder", "555-555-5555");
    phone.addEntry("Michael", "465-858-5555");
    phone.addEntry("Robert", "778-555-1234");
    phone.addEntry("Charlie", "987-546-4564");
    phone.addEntry("Steve", "909-555-7845");
    System.out.println("All of the people in the directory:");
    phone.printListings(); //works
    System.out.println("");
    System.out.println("People with matching area codes:"); //WIP
    phone.printAreaCode("987");
    System.out.println("");
    System.out.println("Prints phone number for requested person:");
    phone.getNumber("Bob the Builder"); //works
}
//Adds a new entry to the phone book (naturally).
//It has two parameters, both Strings: the person’s name and their phone
//number (in the form “610-499-4035”).

public void addEntry(String name, String number) {
    phonebook.put(name, number);
}
//prints the names and phone numbers of everyone in the phone book

private void printListings() {
    for (Iterator<String> it = phonebook.keySet().iterator(); it.hasNext();) {
        for (String p : phonebook.values()) {
            String key = (String) it.next();
            System.out.println(key + ": " + p.toString());
        }
    }
}
//looks up a number in the map.
//It has one parameter (a person’s name) and returns a PhoneNumber object.

public String getNumber(String name) {
    //public void getNumber(String name) {
    // no return statement
    System.out.println(phonebook.get(name));
    return phonebook.get(name);
}
//prints the names of all people with the given area code

public boolean printAreaCode(String areacode) {
    for (String p : phonebook.values()) {
        if (p.startsWith(areacode)) {
            for (String name : phonebook.keySet()) {
                String key = name;
                System.out.println(key);
                return true;
            }
        }
    }
    return false;
    }

    public PhoneBook() {
        phonebook = new HashMap<String, String>();
    }
}

我什至不认为这门课与我的主课交流。 我的老师刚刚说它必须包括在内。 这可能是个问题。

public class PhoneNumber {
    private String areacode;
    private String prefix;
    private String four;

    //Insert a phone number
    public PhoneNumber(String number) {
        String[] parts = number.split("-");
        areacode = parts[0];
        prefix = parts[1];
        four = parts[2];
    }

    @Override
    public String toString() {
        String s = areacode + "-" + prefix + "-" + four;
        return s;
    }
}

【问题讨论】:

  • 你觉得return true;在做什么?
  • 它阻止了 println 打印出所有的名字。我不记得它是否会一直打印一次或两次。无论哪种方式,返回 true;声明阻止它这样做。
  • @MadProgrammer - 忘记标记你了。
  • 使用局部变量作为标志(即found),将其设置为false,当您遍历列表时,每次找到匹配项时,打印出结果并设置标记为true。在方法结束时返回标志
  • 如果我这样做,程序只会打印两次人员列表。 @MadProgrammer

标签: java iterator hashmap


【解决方案1】:

您的地图迭代错误您的 return true; 声明是您的问题的原因,但我们暂时忽略它。

总是像这样遍历地图:

for(Map.Entry<String, String> entry: phoneBook.entrySet())
{
    if(entry.getValue().startsWith(areaCode))
    {
        System.out.println(entry.getKey());
    }
} 

【讨论】:

  • 如果我使用需要我导入某些内容的条目。我无法导入其他任何东西。 @jdb1015
  • 这并不是说 OP 迭代 Map 的方式是“错误的”,它只是效率低下,也许你应该花时间解释“为什么”你的方法更好,否则它只是你说“这样做”,没有任何人应该信任你的真实证据/理由 - 这是一个教育的机会;) - “但我们暂时忽略这一点” - 所以,你已经那时还没有真正回答这个问题?
  • @Minnyme56 为什么不呢? EntryMap 的内部类,所以从技术上讲,您并没有真正导入任何新内容,正如 jdb 所展示的那样,您不需要包含任何导入,您可以通过 Map.Entry
  • 我试过 for(Map.Entry entry: phoneBook.entrySet()) { 它告诉我要导入 java.util.Map; @MadProgrammer
  • @Minnyme56,这有点荒谬,但如果你绝对必须你可以写java.util.Map.Entry&lt;String, String&gt;,你就不必做任何额外的导入。但这是我能想象到的最荒谬的限制。
【解决方案2】:

所以,你需要打印value其中startsWithareaCodekey,所以你的代码基本上有点倒退了。

目前您对寻找匹配项的值进行代码扫描,这没问题,但它会打印所有 key 值?

相反,您需要从每个key 开始,获取value,然后测试以查看与密钥关联的value 是否与areacode 匹配,例如

public boolean printAreaCode(String areacode) {
    boolean found = false;
    for (String key : phonebook.keySet()) {
        String value = phonebook.get(key);
        if (value.startsWith(areacode)) {
            System.out.println(key);
            found = true;
        }
    }
    return found;
}

现在,这非常低效。基本上,对于每次迭代,您都要求Map 查找与key 关联的值,这需要Map 搜索所有它的各种条目/节点,试图找到匹配的键。虽然在您的示例中,这可能不是一个巨大的延迟,但确实应该尽可能避免。

相反,Map 提供对 Entry 的访问,这将 keyvalue 配对到一个对象中,使其访问速度更快,例如...

public boolean printAreaCode(String areacode) {
    boolean found = false;
    for (Map.Entry<String, String> entry : phonebook.entrySet()) {
        String value = entry.getValue();
        if (value.startsWith(areacode)) {
            String key = entry.getKey();
            System.out.println(key);
            found = true;
        }
    }
    return found;
}

现在,HashMapMap 的实现,所以通常情况下,我更喜欢使用

private Map<String, String> phonebook;

而不是

private HashMap<String, String> phonebook;

除非我对仅在 HashMap 中定义的某些功能有特殊需求,否则,如果我稍后使用 TreeMap,代码可能不会在意

【讨论】:

    【解决方案3】:

    你不能添加这条线?! import java.util.Map;

    我很好奇为什么不能添加import 语句;那是标准的一部分还是你不知道怎么做?

    您实际上必须遍历您的地图两次。是的,这是非常低效的代码。

    public boolean printAreaCode(String areacode) {
    boolean haveMatch = false;
    for (String p : phonebook.values()) {
        if (p.startsWith(areacode)) {
            String value = p;
            for (String name : phonebook.keySet()) {
                if(value.equals(phonebook.get(name)) {
                    System.out.println(key);
                    haveMatch = true;
            }
        }
    }
    return haveMatch;
    

    }

    【讨论】:

    • 我唯一可以使用的导入语句是 java.util.HashMap;我的导师对迭代器做了一个例外,因为我们学会了如何使用它,但他说不需要任何其他导入。他还说,大多数方法应该只有 1 行代码(最多 2 行),所以这就是为什么我觉得有些不对劲。 @jdb1015
    • 除非他给你一个编码谜题,否则entrySet() 总是更有效率。给他看我的第一个答案,看看他说什么。我很好奇他是想耍花招还是自己不太了解 Java!
    • 既然他说了大多数方法,我想这可能意味着这个方法不是他所说的“最多”方法之一。
    • 我们还没有学习entrySet()。我认为我们要到下个学期才会考虑这个问题,因为我们已经开始着手继承了。
    • 向他询问entrySet()。很想知道他是否意识到这一点……如果他不知道并且正在教授某种 Java 课程,那将是令人不安的。
    【解决方案4】:

    我相信您的意图只是打印电话号码,其中代码以特定值开头。所以我们不必从方法中返回任何东西,您可以将返回类型设为 void。你可以让它类似于你的printListings

    public void printAreaCode(String areacode) {
        for (String p : phonebook.values()) {
            if (p.startsWith(areacode)) {
                for (String name : phonebook.keySet()) {
                    String key = name;
                    System.out.println(key);
    
                }
            }
        }
    
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-23
      • 1970-01-01
      • 1970-01-01
      • 2020-12-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多