【问题标题】:Iterate over a HashMap with multiple values per key遍历每个键具有多个值的 HashMap
【发布时间】:2018-04-03 15:28:28
【问题描述】:

我目前正在大学学习集合和地图(仍在使用 Java 7)。

他们给了我们一个完成了一半的待办事项列表应用程序。目前待办事项列表采用三个字符串局部变量来允许用户声明工作 (aJob)、执行时间 (aTime) 和执行日期 (aDate)。

该应用程序还有一个实例变量(今天)保存今天的日期。

我需要想出一种方法来检查 HashMap 是否有任何今天到期的任务。所以我需要能够只查询 aDate 局部变量所赋予的 HashMap 值。

我知道要迭代 Maps,我可以将键或值放入 Set 中,然后迭代该集合 - 这不是问题。但是,如果我使用 values() 方法(在 Map 类中)将它们放入一个集合中 - 它会将每个键的所有三个字符串放入集合中。我只想将 aDate 值移动到一个集合中。

有什么想法吗?

我似乎只能找到地图只有一个键和一个值的例子。这个列表有一个键和每个键三个值。

任何指针都会很好?

亲切的问候

编辑.....

只是想我会添加一些代码来提供帮助,因为有几种不同的方法 - 我都非常感激。但不确定它们是否适合我的需求....

作业类是这样构造的......

public Job(String aJob, String aDate, String aTime)
{
  Job = aJob;
  date = aDate;
  time = aTime;
}

然后我在 To Do List 类的实例声明中创建地图......

Map<Integer, Job> toDoList = new HashMap<>();

所以我需要知道迭代此地图的最佳方法,但只有 Job 属性“aDate”可能会保留我所追求的值。

不确定这是否有帮助?

亲切的问候

【问题讨论】:

  • 听起来您正在寻找 Map&lt;K, Set&lt;V&gt;&gt; 或 Guava SetMultimap。 github.com/google/guava/wiki/…
  • 地图怎么样>
  • 那么aJob 是String 还是Job?您的指示非常不清楚且自相矛盾,“不能选择创建新课程”,但在这里您使用 Job 作为地图中值的类型。事实上,你的构造函数根本没有意义,用String aJob,然后Job = aJob...
  • 道歉。希望这可以解决问题。我无法创建任何其他课程,但我们被分配了“作业”课程以作为作业的一部分来完成。所以我们总共有两个类。工作类和待办事项类。 Job 类首先通过在构造函数中采用三个 String 参数来创建。我需要查询 Job 类构造函数中的 aDate String 以查看它是否与今天的日期匹配。
  • 这样的话,托伊森的回答基本上就是你该做的了。只需将Tuple 替换为Job。

标签: java hashmap iteration


【解决方案1】:

如果真的唯一允许您使用的结构是一个 Map,其中每个键都有 3 个值(如果我理解正确的话就是这种情况),其中只有一个是 Date,那么从技术上讲,您可以执行以下操作:

map.values()
    .stream()
    .filter(Date.class::isInstance)
    ...whatever else you want to do

在设计方面,其他建议的解决方案要好得多。

【讨论】:

    【解决方案2】:

    只需创建一个包含您需要的所有数据的类。例如。 如果你需要像 Map&lt;String, Tuple&lt;String, Integer, Date&gt;&gt; 这样奇怪的东西,只需创建一个包含元组的新类:

        class TupleHolder {
        private String firstValue;
        private Integer secondValue;
        private Date thirdValue;
    
        // get/set here...
    }
    

    并使用它:Map&lt;String, TupleHolder&gt;

    【讨论】:

    • 不幸的是,我们得到了关于我们可以做什么和不能做什么的大纲。创建一个新类不是一种选择。我们需要尝试并坚持使用课程材料,但课程材料仅涉及将单个键或单个值放入集合中以对其进行迭代。我们没有涵盖每个键具有多个值的任何地图。
    • 我看到的不使用新对象的方式是使用链表作为第二种泛型类型创建一个映射,然后获取键并在映射及其值上迭代(嵌入循环)。
    【解决方案3】:

    如果您不能按照 Toisen 的建议使用自定义类,也许 HashMap&lt;String, HashMap&lt;String, ArrayList&lt;String&gt;&gt;&gt; 可以为您解决问题。

    我添加了一个如何使用它的示例(以及用一些随机数据填充它)

    public class FunkyMap {
        private HashMap<String, HashMap<String, ArrayList<String>>> jobs;
    
        // For random data
        private String[] job = {"EAT", "SLEEP", "FART", "RELAX", "WORK"};
        private String[] time = {"MORNING", "BEFORENOON", "NOON", "AFTERNOON", "EVENING", "MIDNIGHT"};
        private String[] date = {"FIRST", "SECOND", "THIRD", "FOURTH"};
    
        public FunkyMap() {
            jobs = new HashMap<>();
    
            // To populate some random data
            Random r = new Random();
            for(int i = 0; i < 20; i++) {
                String d = date[r.nextInt(date.length)];
    
                if(jobs.containsKey(d)) {
                    HashMap<String, ArrayList<String>> inner = jobs.get(d);
                    String t = time[r.nextInt(time.length)];
    
                    if(inner.containsKey(t)) {
                        inner.get(t).add(job[r.nextInt(job.length)]);
                    } else {
                        List<String> s = Arrays.asList(new String(job[r.nextInt(job.length)]));
                        inner.put(t, new ArrayList<String>(s));
                    }
                } else {
                    jobs.put(d, new HashMap<String, ArrayList<String>>());
                }
            }
    
            // Actual iteration over date => time => jobs
            Iterator<String> i = jobs.keySet().iterator();
            while(i.hasNext()) {
                String iKey = i.next();
                HashMap<String, ArrayList<String>> inner = jobs.get(iKey);
    
                System.out.println("Jobs scheduled for " + iKey);
    
                Iterator<String> j = inner.keySet().iterator();
                while(j.hasNext()) {
                    String jKey = j.next();
                    ArrayList<String> actualJobs = inner.get(jKey);
    
                    System.out.println("\tAt " + jKey);
    
                    for(String s : actualJobs) {
                        System.out.println("\t\tDo " + s);
                    }
                }
            }
        }
    
        public static void main(String[] args) {
            new FunkyMap();
        }
    }
    

    我冒昧地假设日期是唯一的,并且每个日期的时间都是唯一的,而时间可以容纳任意数量的工作,包括重复。如果最后一个关于工作的假设不成立,您可以将ArrayList&lt;String&gt; 替换为Set&lt;String&gt;。

    【讨论】:

      猜你喜欢
      • 2020-12-27
      • 2012-05-17
      • 2018-09-16
      • 2021-09-10
      • 1970-01-01
      • 2014-04-28
      • 2015-05-11
      • 1970-01-01
      • 2018-03-07
      相关资源
      最近更新 更多