Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I have an HashMap myHashMap, like this:
public static void main(String[] args) {
HashMap<String, UserContact> myHashMap = new HashMap<String, UserContact>(); // first string = username
fillHasmap(myHashMap); // a method to fill my hashmap
HashMap<String, String> usernameAndType = new HashMap<String, String>(); // username , userType
fillUsername(usernameAndType);
myHashMap.entrySet().forEach(p -> p.getValue().setUserType(usernameAndType.get(p))); // does not work.
}
public static void fillHasmap(HashMap<String, UserContact> myHashMap) {
for(int i = 0; i<5; i++) {
UserContact single = new UserContact();
String username = "stack" + i;
single.setUsername(username);
single.setUserType("Client");
single.setUserEmail("temp" + i + "#drop.me");
myHashMap.put(username, single);
}
}
public static void fillUsername(HashMap<String, String> usernameAndType) {
String[] userType = {"Client","Business"};
for(int i = 0; i<5; i++) {
String username = "stack" + i;
Random r = new Random();
int a = r.nextInt(2);
usernameAndType.put(username, usertype[a]);
}
}
The UserContact class is this one:
public class UserContact{
private String username;
private String userType;
private String email;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getUserType() {
return userType;
}
public void setUserType(String userType) {
this.userType = userType;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email= email;
}
}
I want to change all the userType of my UserContact using the one present in the usernameAndType hashmap.
To do It I have used:
myHashMap.entrySet().forEach(p -> p.getValue().setUserType(usernameAndType.get(p)));
But It doensn't work, because I think that without saving it in another hashmap is pointless. So I have tried something like this but I can't compile it because I have an error:
myHashMap= myHashMap.entrySet().forEach(p -> p.getValue().setUserType(usernameAndType.get(p))).collect(HashMap::getKey, HashMap::getValue, this::throwIllegalArgumentException, HashMap::new);
Cannot invoke collect(HashMap::getKey, HashMap::getValue, this::throwIllegalArgumentException, HashMap::new) on the primitive type void
I kwon that I can pass the usernameAndType Hashmap to the method fillHasmap and get the element directly using it, but there is really another way to do it?
If I understand the contents of the two maps correctly, I think the following works as an update in place:
myHashMap
.entrySet()
.forEach(entry ->
entry.getValue().setUserType(usernameAndType.get(entry.getKey())));
Even easier would be to use the following form:
myHashMap
.forEach((key, value) ->
value.setUserType(usernameAndType.get(key)));
Your basic requirement is to construct a new HashMap? Or to mutate the values present in the original HashMap?
If it is to mutate the values present in original HashMap.
myHashMap.values().stream().forEach(val -> val.setUserType(usernameAndType.get(val.getUserName())));
If you need to construct another HashMap with the updated one (Why?!), simply you can do this after the previous step.
Map<String,UserContact> myHashMapNew = new HashMap<>(myHashMap);
There are many things wrong with the code :
First (your code) :
myHashMap= myHashMap.entrySet().forEach(p -> p.getValue().setUserType(usernameAndType.get(p))).collect(HashMap::getKey, HashMap::getValue, this::throwIllegalArgumentException, HashMap::new);
you are calling collect on a non stream. I wont point out the mistakes here but according to your implementation (at least how you'r trying to do it ). This should have been enough to change / mutate the value of the original map without having need to create a new one.
myHashMap.entrySet().forEach(p -> p.getValue().setUserType("someuserType"));
here the p is a Map.Entry (key, value ), and the value is a UserContact so p.getValue() = UserContact then call a setter to the object
Answer : May be for a new map, you wanna do something like this:
Map<String,String> newMap = myHashMap.entrySet()
.stream()
.map(Map.Entry::getValue)
.collect(Collectors.toMap(UserContact::getUsername,UserContact::getUserType));
Shortcut to the above example would be:
Map<String,String> newMap2 = myHashMap.values().stream()
.collect(Collectors.toMap(UserContact::getUsername,UserContact::getUserType))
Assuming that you don't have getters for the userType, try this to create the usernameType hashMap. If you want to modify the original hash map see my second example.
this streams the entrySet of your first map.
creates a new map with the key and the value being the userType.
remember the getValue() returns a UserContact object so you need to dereference it to get the userType
Map<String,String> usernameAndType = myHashMap
.entrySet()
.stream()
.collect(Collectors.toMap(Entry::getKey, e->e.getValue().userType));
If you have getters for your fields, the you can change
e->e.getValue().userType to
e->e.getValue().getUserType() or whatever you named it.
To use the information in the usernameAndType hash map to modify the objects in myHashMap, do the following:
NOTE: You should use a loop to do this because it is considered poor technique to modify external objects from within a stream.
for (Entry<String, UserContact> e : myHashMap.entrySet()) {
UserContact uc = e.getValue();
uc.setUserType(usernameAndType.get(e.getKey());
}
Related
I have a list of custom object,
public class Assignmentsdata {
String assignmentId;
String teacherId;
String groupName;
String sectionId;
String levelId;
String startTime;
}
ArrayList<Assignmentsdata> list = new ArrayList<>();
lets say there are 20 elements in that list.
Now I want to get the output which is a hashmap of startTime as a key and the Value would be a new HashMap of GroupID and a list of Assignments of those that had the same groupName.
OutPut Example
HashMap<startTime,HasMap<groupName,List> hashMap = new HashMap();
a little more insight about the problem: First I want to categorise based on startTime(Month) then i want to categorise based on groupName, Thanks in advance.
I have successfully categorised based on group name and created a map through below code:
for( int i = 0; i<assignmentsdataArrayList.size();i++ ){
if (hashMap.size()>0){
hashMap.get(assignmentsdataArrayList.get(i).getGroupName()).add(assignmentsdataArrayList.get(i));
}else {
hashMap.put(assignmentsdataArrayList.get(i).getGroupName(),new ArrayList<Assignmentsdata>());
hashMap.get(assignmentsdataArrayList.get(i).getGroupName()).add(assignmentsdataArrayList.get(i));
}
}
After that I am lost on how to categorise this hashmap based on the startDate and create a hashmap that would look like the above hashmap in the output heading.
your code may throw a NullPointerException at the first if branch
if (hashMap.size()>0)
{hashMap.get(assignmentsdataArrayList.get(i).getGroupName()).add(assignmentsdataArrayList.get(i));
}
the map.size()>0 doesnt means the Value of GroupName has put a new ArrayList already.
the anwser of using loop should like this
Map<String, Map<String, List<Assignmentsdata>>> map = new HashMap<>();
for (Assignmentsdata assignmentsdata : list) {
if (!map.containsKey(assignmentsdata.getStartTime())) {
map.put(assignmentsdata.getStartTime(), new HashMap<>());
}
Map<String, List<Assignmentsdata>> startTimeMap = map.get(assignmentsdata.startTime);
if (!startTimeMap.containsKey(assignmentsdata.getGroupName())) {
startTimeMap.put(assignmentsdata.getGroupName(), new ArrayList<>());
}
startTimeMap.get(assignmentsdata.groupName).add(assignmentsdata);
}
or you could use the java stream().collect(Collectors.groupingBy()) api to get the result easily
Map<String, Map<String, List<Assignmentsdata>>> result = list.stream()
.collect(Collectors.groupingBy(Assignmentsdata::getStartTime,Collectors.groupingBy(Assignmentsdata::getGroupName)));
I am answering my own question as I solved it if anyone has a better answer please passed your answer aswell, ill accept another answer suitable and efficient answer.
for( int i = 0; i<assignmentsdataArrayList.size();i++ ){
if (hashMap.size()>0){
if (hashMap.get(assignmentsdataArrayList.get(i).getGroupName())==null){
hashMap.put(assignmentsdataArrayList.get(i).getGroupName(),new ArrayList<Assignmentsdata>());
hashMap.get(assignmentsdataArrayList.get(i).getGroupName()).add(assignmentsdataArrayList.get(i));
}else{
hashMap.get(assignmentsdataArrayList.get(i).getGroupName()).add(assignmentsdataArrayList.get(i));
}
}else {
hashMap.put(assignmentsdataArrayList.get(i).getGroupName(),new ArrayList<Assignmentsdata>());
hashMap.get(assignmentsdataArrayList.get(i).getGroupName()).add(assignmentsdataArrayList.get(i));
}
}
// above part is already in the question. the second part i looped through the hashMap then the list once again, and checking if list and map entry have same group name, then made the startdate key that indexed element from the list.
HashMap<String, Map.Entry<String, ArrayList<Assignmentsdata>>> hashMapHashMap = new HashMap<>();
for (var entry : hashMap.entrySet()){
for( int j = 0; j<assignmentsdataArrayList.size();j++ ){
if (assignmentsdataArrayList.get(j).getGroupName()==entry.getKey()){
hashMapHashMap.put(assignmentsdataArrayList.get(j).getStartTime(),entry);
}
}
hashMapHashMap.put(entry.getValue().get())
}
I am reading data from an excel file using apache poi and transforming it into a list of object. But now I want to extract any duplicates based on certain rules into another list of that object and also get the non-duplicate list.
Condition to check for a duplicate
name
email
phone number
gst number
Any of these properties can result in a duplicate. which mean or not an and
Party Class
public class Party {
private String name;
private Long number;
private String email;
private String address;
private BigDecimal openingBalance;
private LocalDateTime openingDate;
private String gstNumber;
// Getter Setter Skipped
}
Let's say this is the list returned by the logic to excel data so far
var firstParty = new Party();
firstParty.setName("Valid Party");
firstParty.setAddress("Valid");
firstParty.setEmail("Valid");
firstParty.setGstNumber("Valid");
firstParty.setNumber(1234567890L);
firstParty.setOpeningBalance(BigDecimal.ZERO);
firstParty.setOpeningDate(DateUtil.getDDMMDateFromString("01/01/2020"));
var secondParty = new Party();
secondParty.setName("Valid Party");
secondParty.setAddress("Valid Address");
secondParty.setEmail("Valid Email");
secondParty.setGstNumber("Valid GST");
secondParty.setNumber(7593612247L);
secondParty.setOpeningBalance(BigDecimal.ZERO);
secondParty.setOpeningDate(DateUtil.getDDMMDateFromString("01/01/2020"));
var thirdParty = new Party();
thirdParty.setName("Valid Party 1");
thirdParty.setAddress("address");
thirdParty.setEmail("email");
thirdParty.setGstNumber("gst");
thirdParty.setNumber(7593612888L);
thirdParty.setOpeningBalance(BigDecimal.ZERO);
secondParty.setOpeningDate(DateUtil.getDDMMDateFromString("01/01/2020"));
var validParties = List.of(firstParty, secondParty, thirdParty);
What I have attempted so far :-
var partyNameOccurrenceMap = validParties.parallelStream()
.map(Party::getName)
.collect(Collectors.groupingBy(Function.identity(), HashMap::new, Collectors.counting()));
var partyNameOccurrenceMapCopy = SerializationUtils.clone(partyNameOccurrenceMap);
var duplicateParties = validParties.stream()
.filter(party-> {
var occurrence = partyNameOccurrenceMap.get(party.getName());
if (occurrence > 1) {
partyNameOccurrenceMap.put(party.getName(), occurrence - 1);
return true;
}
return false;
})
.toList();
var nonDuplicateParties = validParties.stream()
.filter(party -> {
var occurrence = partyNameOccurrenceMapCopy.get(party.getName());
if (occurrence > 1) {
partyNameOccurrenceMapCopy.put(party.getName(), occurrence - 1);
return false;
}
return true;
})
.toList();
The above code only checks for party name but we also need to check for email, phone number and gst number.
The code written above works just fine but the readability, conciseness and the performance might be an issue as the data set is large enough like 10k rows in excel file
Never ignore Equals/hashCode contract
name, email, number, gstNumber
Any of these properties can result in a duplicate, which mean or
Your definition of a duplicate implies that any of these properties should match, whilst others might not.
It means that it's impossible to provide an implementation equals/hashCode that would match the given definition and doesn't violate the hashCode contract.
If two objects are equal according to the equals method, then calling the hashCode method on each of the two objects must produce the same integer result.
I.e. if you implement equals in such a way they any (not all) of these properties: name, email, number, gstNumber could match, and that would enough to consider the two objects equal, then there's no way to implement hashCode correctly.
And as the consequence of this, you can't use the object with a broken equals/hashCode implementation in with a hash-based Collection because equal objects might end up the in the different bucket (since they can produce different hashes). I.e. HashMap would not be able to recognize the duplicated keys, hence groupingBy with groupingBy() with Function.identity() as a classifier function would not work properly.
Therefore, to address this problem, you need to implement equals() based on all 4 properties: name, email, number, gstNumber (i.e. all these values have to be equal), and similarly all these values must contribute to hash-code.
How to determine Duplicates
There's no easy way to determine duplicates by multiple criteria. The solution you've provided is not viable, since we can't rely on the equals/hashCode.
The only way is to generate a HashMap separately for each end every attribute (i.e. in this case we need 4 maps). But can we alternate this, avoiding repeating the same steps for each map and hard coding the logic?
Yes, we can.
We can create a custom generic accumulation type (it would be suitable for any class - no hard-coded logic) that would encapsulate all the logic of determining duplicates and maintain an arbitrary number of maps under the hood. After consuming all the elements from the given collection, this custom object would be aware of all the duplicates in it.
That's how it can be implemented.
A custom accumulation type that would be used as container of a custom Collector. Its constructor expects varargs of functions, each function correspond to the property that should be taken into account while checking whether an object is a duplicate.
public static class DuplicateChecker<T> implements Consumer<T> {
private List<DuplicateHandler<T>> handles;
private Set<T> duplicates;
#SafeVarargs
public DuplicateChecker(Function<T, ?>... keyExtractors) {
this.handles = Arrays.stream(keyExtractors)
.map(DuplicateHandler::new)
.toList();
}
#Override
public void accept(T t) {
handles.forEach(h -> h.accept(t));
}
public DuplicateChecker<T> merge(DuplicateChecker<T> other) {
for (DuplicateHandler<T> handler: handles) {
other.handles.forEach(handler::merge);
}
return this;
}
public DuplicateChecker<T> finish() {
duplicates = handles.stream()
.flatMap(handler -> handler.getDuplicates().stream())
.flatMap(Set::stream)
.collect(Collectors.toSet());
return this;
}
public boolean isDuplicate(T t) {
return duplicates.contains(t);
}
}
A helper class representing a single createrion (like name, email, etc.) which encapsulates a HashMap. keyExtractor is used to obtain a key from an object of type T.
public static class DuplicateHandler<T> implements Consumer<T> {
private Map<Object, Set<T>> itemByKey = new HashMap<>();
private Function<T, ?> keyExtractor;
public DuplicateHandler(Function<T, ?> keyExtractor) {
this.keyExtractor = keyExtractor;
}
#Override
public void accept(T t) {
itemByKey.computeIfAbsent(keyExtractor.apply(t), k -> new HashSet<>()).add(t);
}
public void merge(DuplicateHandler<T> other) {
other.itemByKey.forEach((k, v) ->
itemByKey.merge(k,v,(oldV, newV) -> { oldV.addAll(newV); return oldV; }));
}
public Collection<Set<T>> getDuplicates() {
Collection<Set<T>> duplicates = itemByKey.values();
duplicates.removeIf(set -> set.size() == 1); // the object is proved to be unique by this particular property
return duplicates;
}
}
And that is the method, responsible for generating the map of duplicates, that would be used from the clean code. The given collection would be partitioned into two parts: one mapped to the key true - duplicates, another mapped to the key false - unique objects.
public static <T> Map<Boolean, List<T>> getPartitionByProperties(Collection<T> parties,
Function<T, ?>... keyExtractors) {
DuplicateChecker<T> duplicateChecker = parties.stream()
.collect(Collector.of(
() -> new DuplicateChecker<>(keyExtractors),
DuplicateChecker::accept,
DuplicateChecker::merge,
DuplicateChecker::finish
));
return parties.stream()
.collect(Collectors.partitioningBy(duplicateChecker::isDuplicate));
}
And that how you can apply it for your particular case.
main()
public static void main(String[] args) {
List<Party> parties = // initializing the list of parties
Map<Boolean, List<Party>> isDuplicate = partitionByProperties(parties,
Party::getName, Party::getNumber,
Party::getEmail, Party::getGstNumber);
}
I would use create a map for each property where
key is the property we want to check duplicate
value is a Set containing all the index of element in the list with same key.
Then we can
filter values in the map with more that 1 index (i.e. duplicate indexes).
union all the duplicate index
determine if the element is duplicate/unique by using the duplicate index.
The time complexity is roughly O(n).
public class UniquePerEachProperty {
private static void separate(List<Party> partyList) {
Map<String, Set<Integer>> nameToIndexesMap = new HashMap<>();
Map<String, Set<Integer>> emailToIndexesMap = new HashMap<>();
Map<Long, Set<Integer>> numberToIndexesMap = new HashMap<>();
Map<String, Set<Integer>> gstNumberToIndexesMap = new HashMap<>();
for (int i = 0; i < partyList.size(); i++) {
Party party = partyList.get(i);
nameToIndexesMap.putIfAbsent(party.getName(), new HashSet<>());
nameToIndexesMap.get(party.getName()).add(i);
emailToIndexesMap.putIfAbsent(party.getEmail(), new HashSet<>());
emailToIndexesMap.get(party.getEmail()).add(i);
numberToIndexesMap.putIfAbsent(party.getNumber(), new HashSet<>());
numberToIndexesMap.get(party.getNumber()).add(i);
gstNumberToIndexesMap.putIfAbsent(party.getGstNumber(), new HashSet<>());
gstNumberToIndexesMap.get(party.getGstNumber()).add(i);
}
Set<Integer> duplicatedIndexes = Stream.of(
nameToIndexesMap.values(),
emailToIndexesMap.values(),
numberToIndexesMap.values(),
gstNumberToIndexesMap.values()
).flatMap(Collection::stream).filter(indexes -> indexes.size() > 1)
.flatMap(Set::stream).collect(Collectors.toSet());
List<Party> duplicatedList = new ArrayList<>();
List<Party> uniqueList = new ArrayList<>();
for (int i = 0; i < partyList.size(); i++) {
Party party = partyList.get(i);
if (duplicatedIndexes.contains(i)) {
duplicatedList.add(party);
} else {
uniqueList.add(party);
}
}
System.out.println("duplicated:" + duplicatedList);
System.out.println("unique:" + uniqueList);
}
public static void main(String[] args) {
separate(List.of(
// name duplicate
new Party("name1", 1L, "email1", "gstNumber1"),
new Party("name1", 2L, "email2", "gstNumber2"),
// number duplicate
new Party("name3", 3L, "email3", "gstNumber3"),
new Party("name4", 3L, "email4", "gstNumber4"),
// email duplicate
new Party("name5", 5L, "email5", "gstNumber5"),
new Party("name6", 6L, "email5", "gstNumber6"),
// gstNumber duplicate
new Party("name7", 7L, "email7", "gstNumber7"),
new Party("name8", 8L, "email8", "gstNumber7"),
// unique
new Party("name9", 9L, "email9", "gstNumber9")
));
}
}
Assume Party has below constructor and toString()(for testing)
public class Party {
public Party(String name, Long number, String email, String gstNumber) {
this.name = name;
this.number = number;
this.email = email;
this.address = "";
this.openingBalance = BigDecimal.ZERO;
this.openingDate = LocalDateTime.MIN;
this.gstNumber = gstNumber;
}
#Override
public String toString() {
return "Party{" +
"name='" + name + '\'' +
", number=" + number +
", email='" + email + '\'' +
", gstNumber='" + gstNumber + '\'' +
'}';
}
...
}
This question already has answers here:
Why do I need to override the equals and hashCode methods in Java?
(31 answers)
Closed 2 years ago.
So I have an ArrayList with objects that have name, id, salary etc. And a Queues with another ArrayList objects, model, year etc.
I created a HashMap and used the ArrayList objects as keys and the queues as values, associating each queue for a object in the arraylist.
The thing is, I have to list all the values for a determined key.
I would like to know how can I return all the values of a hashmap depending on the name value of the object.
For example this my map:
{Mech [Name = Ella McCarthy , ID = 1]=[Car [model=Civic, year=2010, fix=flat tyres], Car [model=Audi A3, year=2012, fix=something broken]],
Mech [Name = Josh Reys , ID = 1]=[Car [model=Cruze, year=2014, fix=something broken], Car [model=Impala, year=1990, fix=something broken]]}
Is there any way of returning the value if the name in the object in the key equals to Ella McCarthy?
Next code may comprehensive for you:
public class MapExample {
private static final String DETERMINED_KEY = "Ella McCarthy";
Queue<Car> queue = new PriorityQueue<>();
Map<Mech, Queue<Car>> map = new HashMap<>();
Queue<Car> getValuesByNameInKeyObjectWithStreams() {
Queue<Car> cars = map.entrySet()
.stream()
.filter(mapEntry -> mapEntry.getKey().getName().contentEquals(DETERMINED_KEY))
.map(Map.Entry::getValue)
.findFirst()
.orElseThrow(); // Throw exception if did't find according value. Or return another result with orElse(result)
return cars;
}
Queue<Car> getValuesByNameInKeyObjectBeforeJava8() {
for (Map.Entry<Mech, Queue<Car>> entry : map.entrySet()) {
String mechName = entry.getKey().getName();
if (mechName.equals(DETERMINED_KEY)) {
return entry.getValue();
}
}
// Throw exception or return another result
throw new RuntimeException("If didn't find exception");
}
}
class Mech {
String name;
public String getName() {
return name;
}
}
class Car {
String value;
}
If you prefer functional style and use java 8 or higher, peek getValuesByNameInKeyObjectWithStreams method.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
I have the following data stored in a ".txt" file:
Dave,40,04/05/1978
Scott,34,05/06/1986
Sam,24,04/05/1978
Love,32,04/06/1989
Harry,29,04/06/1989
I have used the BufferedReader to read, split (using ,) and store it in a String[] stringArray.
Now stringArray[0] will have name, stringArray[1] will have number and stringArray[2] will have date.
I am now looking to build a HashMap like below to display the key as date (in String) and value as List of Members having the same date of birth
Expected output:
DOBMap: {04-05-1978=[[Dave,40],[Same,24]], 05/06/1986=[[Scott,34]], 04/06/1989=[[Love,32],[Harry,29]]
I have Member which has the following variables:
private String name;
private String no;
private String DOB;
Since I am a novice for collections, I am seeking help to achieve this DOBMap output.
I think you can do better by using Java Stream API (https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html).
Here I assume that your Memeber class has the constructor:
Member(String[] array)
In which case the following:
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;
import static java.util.stream.Collectors.groupingBy;
public class SO1 {
public static void main(String[] args) {
String filePath = ".../src/main/resources/SO1.txt";
try (Stream<String> lines = Files.lines(Paths.get(filePath))) {
Map<String, List<Member>> map = lines
.map(line -> line.split(","))
.map(Member::new)
.collect(groupingBy(Member::getDOB));
System.out.println(map);
} catch (Exception e) {
e.printStackTrace();
}
}
}
prints:
{05/06/1986=[Member{name='Scott', no='34', dob='05/06/1986'}], 04/05/1978=[Member{name='Dave', no='40', dob='04/05/1978'}, Member{name='Sam', no='24', dob='04/05/1978'}], 04/06/1989=[Member{name='Love', no='32', dob='04/06/1989'}, Member{name='Harry', no='29', dob='04/06/1989'}]}
Arguably, the intent of this code is more clear then a code that iterates explicitly.
You could just iterate through all of the members and insert them in a HashMap. I used ArrayList in this example, but if you would like, I can rewrite it with a regular array.
So lets say you have an ArrayList called members.
// members is an ArrayList of Member objects
HashMap<String, ArrayList<ArrayList<String>>> dobMap = new HashMap<>();
for (Member m : members) {
String[] temp = {m.getName(), m.getNo()}; // e.g. [Dave, 40]
// already in the map, so just push it to the existing ArrayList in there
if (dobMap.containsKey(m.getDOB())) {
dobMap.get(m.getDOB()).add(temp); // e.g. [[Dave, 40]].add([Sam, 24])
} else { // not in the map yet, so push a new ArrayList to that spot
ArrayList<String[]> temp2 = new ArrayList<>();
temp2.add(temp); // e.g. [[Dave, 40]]
dobMap.put(m.getDOB(), temp2);
}
}
A slightly different solution (using an ArrayList of ArrayList instead of an ArrayList of String[]):
HashMap<String, ArrayList<ArrayList<String>>> dobMap = new HashMap<>();
for (Member m : members) {
ArrayList<String> temp = new ArrayList<>();
temp.add(m.getName());
temp.add(m.getNo());
if (dobMap.containsKey(m.getDOB())) {
dobMap.get(m.getDOB()).add(temp);
} else {
ArrayList<ArrayList<String>> temp2 = new ArrayList<>();
temp2.add(temp);
dobMap.put(m.getDOB(), temp2);
}
}
With that, you can simply run System.out.println(dobMap); and see that the result is exactly as you expect. Printing the HashMap from the first solution will require some effort to print out the contents of the HashMap since it won't print the regular array nicely like it does for ArrayList. But they both store the information in the same way.
But I think instead of storing an ArrayList of ArrayList, you should just be storing it as an ArrayList of Member. So I will show a third solution, which is this:
HashMap<String, ArrayList<Member>> dobMap = new HashMap<>();
for (Member m : members) {
if (dobMap.containsKey(m.getDOB())) {
dobMap.get(m.getDOB()).add(m);
} else {
ArrayList<Member> temp = new ArrayList<>();
temp.add(m);
dobMap.put(m.getDOB(), temp);
}
}
And then override toString() in Member like so:
#Override
public String toString() {
return String.format("[%s, %s]", this.name, this.no);
}
This third solution seems to be the most clear.
In this example, I used the following Member class as a basis:
class Member {
private String name, no, dob;
public Member(String name, String no, String dob) {
this.name = name;
this.no = no;
this.dob = dob;
}
public String getName() { return this.name; }
public String getNo() { return this.no; }
public String getDOB() { return this.dob; }
}
An example of how you might define your ArrayList of Member object would be:
// parts is an array of length 3 like you said
ArrayList<Member> members = new ArrayList<>();
members.add(new Member(parts[0], parts[1], parts[2]);
I have a for loop from a JSONarray and I add the values to a LinkedHashMap. I would like to avoid adding identical values. I don't know how to do this.
for (int l = 0; l <stops_summaries2.length(); l++){
JSONObject stopObject2 = stops_summaries2.getJSONObject(l);
String stopid2 = stopObject2.getString("id");
System.out.println("stopid2 --->" + stopid2);
String stopurl2 = stopObject2.getString("url");
System.out.println("stopurl2 --->" + stopurl2);
String stopname2 = stopObject2.getString("name");
System.out.println("stopname2 --->" + stopname2);
LinkedHashMap<String, Object> map = new LinkedHashMap<String, Object>();
map.put(TAG_NAME, stopname2);
map.put(TAG_SHORT, id);
map.put(TAG_COLOR, stopid2);
itemList.add(map);
}
You can use the functions containsKey(key) and containsValue(values) to check if the map contains a certain key or value.
Edit: I see now that you are creating a new Map on each iteration, is that really what you want to do? That map will not be available outside of the for loop. I think you need to declare the Map before the for loop and then add to it.
Edit: corrected a mistake in my answer,
In my opinion you should avoid to create a different map at each iteration and use it like a container for your data. You could have a wrapper class:
public class Item {
String name;
String id;
String url;
public Item(String nane, String id, String url) {
this.name = name;
this.id = id;
this.url = url;
}
#Override
public boolean equals(Object other){
if (!(other instanceof Item)) return false;
return id.equals( ((Item)other).id);
}
}
and override equals to check if two objects are equals.