MTA
MTA

Reputation: 799

Iterate over two TreeMap at the same time in Java

I have two maps:

 Map<Date, List<Journey>> journeyMap = new TreeMap<Date, List<Journey>>
 Map<Date, List<Job>> jobMap = new TreeMap<Date, List<Job>>

I used TreeMap because that means they're sorted by date but I want to go through both maps at the same time, get the values of Journey/Job, then do some work.

I think i could use generics, storing the Job/Journey as an Object, then checking the instanceOf but I'm not sure if thats the solution?

Thanks.

Upvotes: 1

Views: 986

Answers (3)

Soana
Soana

Reputation: 711

Even though the others are right, that there are better, safer and more comfortable ways to achive whatever you want, it is possible to iterate over (the entries of) two Maps (aka Collections) at the same time.

//replace keySet() with your favorite method in for-each-loops
Iterator<Date> journeyIterator = journeyMap.keySet().iterator()
Iterator<Date> jobIterator = jobMap.keySet().iterator();
while(journeyIterator.hasNext() && jobIterator.hasNext()){
    Date journeyDate = journeyIter.next()
    Date jobDate = jobIterator.next();
    //... do whatever you want with the data
}

This code does explicitly, what a for-each-loop can do implicitly for one Collection. It retrieves the Iterator and gets the element from the Collection from it, much like reading a file.

Upvotes: 1

Alex Salauyou
Alex Salauyou

Reputation: 14338

Yes, defining a new class for that is definitely the solution, because it composes related objects together, which is very welcomed in OOP. And you should not forget to implement hashCode() and equals() methods to make such classes work properly in Java collections:

public final class JourneyJob {
   final Journey journey;
   final Job job;

   public JourneyJob(Journey journey, Job job) {
       if (journey == null || job == null)
            throw new NullPointerException();
       this.journey = journey;
       this.job = job;
   }

   public int hashCode() {
       return Objects.hash(journey, job);
   }

   public boolean equals(JourneyJob other) {
       return other.job.equals(job) && other.journey.equals(journey);
   }
}

To add elements to common Map:

Map<Date, List<JourneyJob>> map = new TreeMap<>();
...

if (map.contains(date)) {
   map.get(date).add(new JourneyJob(journey, job));
} else {
   map.put(date, new ArrayList<>(Arrays.asList(new JourneyJob(journey, job)));
}

...

To retrieve JourneyJob objects:

for (List<JourneyJob> jjList : map.values()) {
    for (JourneyJob jj : jjList) {
       journey = jj.journey;
       job = jj.job;
       //... do your work here
    }
}

Or, if you use Java 8, this can be done using nested forEach():

map.values().stream().forEach(list ->
    list.stream().forEach(jj -> {
       Journey journey = jj.journey;
       Job job = jj.job;
       //... do your work here
    })
);

Upvotes: 0

davidluckystar
davidluckystar

Reputation: 928

You're making an assumption that these maps are having values sorted in the very same way, but this is definitely not correct. At least if you want to write a logic like this you need to declare the same implementing class as a reference:

TreeMap<Date, List<Journey>> journeyMap = new TreeMap<Date, List<Journey>>
TreeMap<Date, List<Job>> jobMap = new TreeMap<Date, List<Job>>

but believe me you don't want to do it.

You're right! Instead doing 2 maps create 1, holding pair of Job/Journey objects - create a JobJourneyHolder class which holds both objects, this will be a good solution.

Upvotes: 0

Related Questions