Getting duplicate values while comparing with the map - java

Initially i will be selecting a list of student names in a page and submit for getting the address details.StudentNames will be stored in the studentDetailMapList.While looping through the list , i will compare the student names with the AddressDetailsMap to retrieve the addressDetails.But when there are students with same names , the first iteration returns the exact address but when the second iteration happens , it again returns the 1st student address instead of the second student address.It is getting the duplicate values
for (i=studentDetailMapList.values().iterator;i.hasNext();)
{
detailMap = (Map)i.Next();
sDetails = (StudentDetails)detailMap.get("Student");
student = sDetails.getRollNo();
StudentAddressDetails studentAddressDetails = getDetailswithAddress(AddressDetailsMap,sDetails);
}
private StudentAddressDetails getDetailswithAddress(Map AddressDetailsMap,sDetails student)
{
StudentAddressDetails addDetails = null;
try{
for(Iterator itr = AddressDetailsMap.values().iterator();itr.hasNext();){
addDetails = (StudentAddressDetails )itr.next();
if( (addDetails != null) && (addDetails.getStudentID().equals(student.getId()))){
return addDetails;
}
}
}catch(Throwable t){
return null;
}
return null;
}
Is there a way to avoid the duplicate while comparing with the map?
Thanks a lot.

The problem you are having is that you are using the the map data structure wrong.
A map is an object that maps keys to values. A map cannot contain duplicate keys; each key can map to at most one value.
You can not have multiple addresses for the same name, you should use other property for the map, maybe a Student ID, even the list's index should work in this case.

You have to add a UUID in your student's class and work with it for managing their data
EDIT for response
Java's UUID give you the basic Java's UUID.
you can manage your own sequence - This way may be helpfull for indexing Students in database with UNIQUE_ID.
The best thing to manage your IDs : use a HashMap<Integer,Student>.

Each key of your AddressDetailsMap map must be an identifier (studentId) and not the student name.
EDIT:
In this case, your method should look like this:
private StudentAddressDetails getDetailswithAddress(Map AddressDetailsMap,sDetails student) {
return AddressDetailsMap.get(student.getStudentID());
}

Related

How to know if an object exist in arraylist or no based on one variable in it

I am having array list let's consider it for users . Each user object has a variable called id I tried to use contains methods with the same object exactly but I surprised that it isn't working.. How can I know if the list contains a user with an id that I am looking for without looping on the list elements? I know that I can use loop but I am looking for a better way to do that
Contains in array list is always linear complexity meaning that it always loops through the elements. If you want your contains to work the way you intended you could override equals and make it use the id field in User class. Another way to solve this problem would be to not use array list but HashMap with your ID as a key and a user as value or maybe even a HashSet as it always uses equals before adding elements to the collection.
public class UserList extends ArrayList<User> {
#Override
public boolean contains(Object o) {
Object[] arr = this.toArray();
for (Object obj:arr) {
if(obj.toString().equals(String.valueOf(o))){
return true;
}
}
return false;
}}
class User {
String id;
String name;
#Override
public String toString() {
return id;
}
}
If you did not override equals in your User class, it will check if it is the same instance, not if the field values are equals.
If you don't want to override equals, using only the id, you can keep the users in a
Map<String,User> users; => users.containsKey(id)
where the key is the id, or keep just the ids in a separate
Set<String> ids; and call contains. => ids.contains(id)
As you mentioned, it is possible to iterate the array list to get the answer. If you do not want to do it, you can just copy the values into a hash map like:
Map<String, User> userMap = new HashMap();
for (int i=0; i<arrayList.size(); i++) {
userMap.put(arrayList.get(i).getId(), arrayList.get(i));
}
String isExist = userMap.containsKey(id);
Lets say you want to select user with id=23, using stream,
List<User> usersLlist = New LinkedList<>();
User user;
user = usersLlist.stream().filter( user -> user.id == 23).findAny();
if you are using a get method to get user id
user = usersLlist.stream().filter( user -> user.getId() == 23).findAny();

Java hashmap with Multiple values

I Know its been asked a hundred times, and the answer is always the same, You Can not use multiple repeating values in a hashmap.
But lets get to the problem. I have an import file, the import file has information around the lines of a CustomerID, a ProductID, and Units sold (its a basic Receipt format).
What I want to do is take the import, put it into a map, and be able to reference it.
Map<integer,DoubleSales> hashmap = new HashMap <integer,DoubleSales>
try {
Scanner dataFile = new Scanner 9new File ("./salesData.csv"));
dataFile.nextLine();
while(dataFile.hasNextLine()){
String[] lineValues = line.split (",");
Integer CustomerID = Integer.parseInt(lineValues[0]);
Integer ProductID = Integer.parseInt(lineValues[1]);
integer Units = Integer.parseInt(lineValues[2]);
DoubleSales sales = new DoubleSales(CustomerID,ProductID,Units);
ProductData.put(CustomerID,sales);
}
class DoubleSales{
int CustomerID;
int ProductID;
int Units;
DoubleSales(int custID, int prodID, int Units){
CustomerID = custID;
ProductID = prodID;
Units = units;
}
}
The import file has data in the format of
CustomerID, ProductID, UnitsSold
1,10002,3
1,10004,5
1,10008,2
1,10010,3
1,10010,3
Using the code up there, When I print the customerID value of 1, I get just the last entry which is 10010,3.
How would I do it to print out, all values of CustomerID 1, and the Units sold?
for example:
1,10002,3
10004,5
10008,2
10010,3
10010,3
(will add the two 10010 values later.)
I do not wish to Use array lists.
Try MultiValueMap from Apache Common Collections.
Click here for more reference
In your case, a simple Map won't do your favor, everything you write to the value of a specified customer will be overridden, if you want to retain all entries while keeping them easily referenced, try:
First, create a structured map
Map<Integer,List<DoubleSales>> productData = new HashMap<Integer,List<DoubleSales>>();
Second, add products like this
List<DoubleSales> entries;
if(productData.get(CustomerID) == null) {
entries = new ArrayList<DoubleSales>();
entries.add(sales);
productData.put(CustomerID, entries);
} else {
List<DoubleSales> entries = productData.get(CustomerID);
entries.add(sales);
}
Third, review your products list that you just added
List<DoubleSales> products = productData.get(CustomerID);
if (products != null) {
for(DoubleSales product : products) {
// access your product here.
}
}
You have duplicated CustomerID (all having 1 as id) and you using that as a key in Hashmap. That is the reason it is keep ovverding when you insert a new record with the same id. Looks like your product id is unique. Try that or have unique customer id.
I think in that case it is better to implement the structure with a matrix. It could be done easily with arrays (or lists), where rows could contain a bean formed by the product id and the units sold, being indexed by the customer id
My first idea was Jerry Chin's solution, but I would like to show you a second approach, just to demonstrate that there are multiple solutions to the same problem.
You could store your values in a TreeSet<DoubleSales>. This would not limit the entries, you can enter for example 1,10010,3 as many times as you want.
Then, define an ordering (Comparator) on the DoubleSales, to group the orders by CustomerID.
When you print your list, you can check if the customerID of the current record is different from the prevoius record. If different, then it is the first record of the new customer. If not, it belongs to the same customer.
And the code:
SortedSet<DoubleSales> set = new TreeSet<DoubleSales>(new Comparator<DoubleSales>() {
#Override
public int compare(DoubleSales o1, DoubleSales o2) {
return Long.compare(o1.customerId, o2.customerId);
}
});
// ... import data
set.add(new DoubleSales( /*...*/ ));
// iterate through data
DoubleSales prevDS = null;
for (DoubleSales ds : set) {
if (prevDS == null || ds.customerId != prevDS.customerId) {
// first record of a customer
// print CustomerID, ProductID, UnitsSold
} else {
// second or next record of a customer
// print ProductID, UnitsSold only
}
prevDS = ds;
}

LinkedList object add() function not updating values - java

I am creating an inverted index dictionary, which takes a million or so tweets from a file, stores the words from these tweets as the Keys in the dictionary (HashMap) and a pointer to a postings list (LinkedList) which contains the document ID (tweet username, date etc.) as the Value of the key.
My function stores the words as the key for the HashMap with no problem and should store an object pointer to the postings list for each occurrence of the word as the value for the key. But for some reason when I try to update the list it doesn't work. Once the entire file has been read through, the HashMap contains the keys with null Objects as their values.
The code here:
String line = scanner.nextLine();
String[] lineArr = line.split(" ");
DocID id = new DocID(lineArr[0], lineArr[1],lineArr[2]);
for(int i=3; i<lineArr.length; i++){
ListPointer list = new ListPointer();
if(dict.containsKey(lineArr[i].toLowerCase())) list = dict.get(lineArr[i]);
list.postings.add(id);
dict.put(lineArr[i].toLowerCase(), list);
}
}
should store an Object with a list attribute as the value, effectively acting as a pointer to a list. If a similar key exists in the table, the value is obtained and the list attribute of that value should be updated and set again as the value for that key.
I know using a LinkedList as the value of the HashMap rather than using an object containing an inherent list would be better, but we were instructed that the postings list should be stored separately and shouldn't be an attribute of the dictionary class, and the dictionary should just contain a pointer to its relevant postings list.
So far these are the objects with their members:
public static HashMap<String, ListPointer> dict;
public static class DocID{
public String userID;
public String date;
public String time;
public DocID(String dte, String tme, String id){
this.userID = id;
this.date = dte;
this.time = tme;
}
}
public static class ListPointer{
public static LinkedList<DocID> postings;
public ListPointer(){
postings = new LinkedList<DocID>();
}
}
I could understand if it was an overwriting error, but no, the value of each key in the HashMap upon complete read through of the file is null and I have no idea why this could be?
Your postings member shouldn't be static. You have a single instance shared across all ListPointer instances, and you overwrite it with an empty LinkedList<DocID> each time the ListPointer constructor is invoked.
Change
public static LinkedList<DocID> postings;
to
public LinkedList<DocID> postings;
EDIT :
You have another problem in the retrieval from the Map :
Change
if(dict.containsKey(lineArr[i].toLowerCase())) list = dict.get(lineArr[i]);
to
if(dict.containsKey(lineArr[i].toLowerCase())) list = dict.get(lineArr[i].toLowerCase());
If you are passing a lower case String to containsKey, you must pass the same lower case String to get. Otherwise get will return null if the original key wasn't lower case.
I see two issues:
Issue 1.
public static class ListPointer{
public static LinkedList<DocID> postings;
...
The class ListPointer does not need to be static and the member "postings" does not to be static either.
Issue 2
if(dict.containsKey(lineArr[i].toLowerCase())) list = dict.get(lineArr[i]);
I think the main problem is in this line. you are trying to match everything in lower case, but when you get the key from dict you aren't using .toLowerCase()

Arraylist element name already exists, update otherwise create new one in java

I have trying to get the string value from the arraylist values.
But In my arraylist if the value already exists , just update the count . otherwise need to create a new one. Here values are updating, but how can i create a new one element if the name didn't match with the arraylist element name? Please tell me , how can i verify the element(GlobalData.getCRole) already exists in the arraylist.
In this code the arraylist name is GlobalData.getrolecount
GlobalData.getCRole = item.getRole_name();
if (GlobalData.getrolecount.size() > 0) {
for (int i = 0; i < GlobalData.getrolecount.size(); i++) {
Role getrc = GlobalData.getrolecount.get(i);
Role getrcverify = new Role();
getrcverify.setRole_name(GlobalData.getCRole);
if (getrc.getRole_name().equalsIgnoreCase(GlobalData.getCRole)) {
String inccount = GlobalData.getrolecount.get(i).getCount();
int getcount = Integer.parseInt(inccount) + 1;
getrc.setCount(Integer.toString(getcount));
}
}
} else {
Role getrc = new Role();
getrc.setRole_name(GlobalData.getCRole);
getrc.setCount("1");
GlobalData.getrolecount.add(getrc);
}
Adding to #GabeSechan's answer, here's a snippet that would help you:
//let's say you store your data in a Map called myHashMap
String keyToMatch = "your_key_here"; // replace this line with whatever code you use to get your key
if(myHashMap.containsKey(keyToMatch)) // Check if your map already contains the key
{
int val = myHashMap.get(keyToMatch);
myHashMap.put(keyToMatch, val++); // Can be shrunken to a single line
}
else
{
myHashMap.put(keyToMatch, 1); // If it doesn't exist in the map, add it (with count 1)
}
This code can be shrunken much more because Map<> is a very robust tool. But I've written it in a way similar to your implementation so you can understand it better.
Let me know if you need further explanation or help trying to init myHashMap.
I'd use a different data structure. A list isn't what you want. You want a Map (probably a HashMap) of strings to Count, or of strings to Roles. That way you can do O(1) searches to see if a role already exists, rather than an O(n) walk of the list, and checking if the role exists is a simple check to see if get returns null.

how to manipulate list in java

Edit: My list is sorted as it is coming from a DB
I have an ArrayList that has objects of class People. People has two properties: ssn and terminationReason. So my list looks like this
ArrayList:
ssn TerminatinoReason
123456789 Reason1
123456789 Reason2
123456789 Reason3
568956899 Reason2
000000001 Reason3
000000001 Reason2
I want to change this list up so that there are no duplicates and termination reasons are seperated by commas.
so above list would become
New ArrayList:
ssn TerminatinoReason
123456789 Reason1, Reason2, Reason3
568956899 Reason2
000000001 Reason3, Reason2
I have something going where I am looping through the original list and matching ssn's but it does not seem to work.
Can someone help?
Code I was using was:
String ssn = "";
Iterator it = results.iterator();
ArrayList newList = new ArrayList();
People ob;
while (it.hasNext())
{
ob = (People) it.next();
if (ssn.equalsIgnoreCase(""))
{
newList.add(ob);
ssn = ob.getSSN();
}
else if (ssn.equalsIgnoreCase(ob.getSSN()))
{
//should I get last object from new list and append this termination reason?
ob.getTerminationReason()
}
}
To me, this seems like a good case to use a Multimap, which would allow storing multiple values for a single key.
The Google Collections has a Multimap implementation.
This may mean that the Person object's ssn and terminationReason fields may have to be taken out to be a key and value, respectively. (And those fields will be assumed to be String.)
Basically, it can be used as follows:
Multimap<String, String> m = HashMultimap.create();
// In reality, the following would probably be iterating over the
// Person objects returned from the database, and calling the
// getSSN and getTerminationReasons methods.
m.put("0000001", "Reason1");
m.put("0000001", "Reason2");
m.put("0000001", "Reason3");
m.put("0000002", "Reason1");
m.put("0000002", "Reason2");
m.put("0000002", "Reason3");
for (String ssn : m.keySet())
{
// For each SSN, the termination reasons can be retrieved.
Collection<String> termReasonsList = m.get(ssn);
// Do something with the list of reasons.
}
If necessary, a comma-separated list of a Collection can be produced:
StringBuilder sb = new StringBuilder();
for (String reason : termReasonsList)
{
sb.append(reason);
sb.append(", ");
}
sb.delete(sb.length() - 2, sb.length());
String commaSepList = sb.toString();
This could once again be set to the terminationReason field.
An alternative, as Jonik mentioned in the comments, is to use the StringUtils.join method from Apache Commons Lang could be used to create a comma-separated list.
It should also be noted that the Multimap doesn't specify whether an implementation should or should not allow duplicate key/value pairs, so one should look at which type of Multimap to use.
In this example, the HashMultimap is a good choice, as it does not allow duplicate key/value pairs. This would automatically eliminate any duplicate reasons given for one specific person.
What you might need is a Hash. HashMap maybe usable.
Override equals() and hashCode() inside your People Class.
Make hashCode return the people (person) SSN. This way you will have all People objects with the same SSN in the same "bucket".
Keep in mind that the Map interface implementation classes use key/value pairs for holding your objects so you will have something like myHashMap.add("ssn",peopleobject);
List<People> newlst = new ArrayList<People>();
People last = null;
for (People p : listFromDB) {
if (last == null || !last.ssn.equals(p.ssn)) {
last = new People();
last.ssn = p.ssn;
last.terminationReason = "";
newlst.add(last);
}
if (last.terminationReason.length() > 0) {
last.terminationReason += ", ";
}
last.terminationReason += p.terminationReason;
}
And you get the aggregated list in newlst.
Update: If you are using MySQL, you can use the GROUP_CONCAT function to extract data in your required format. I don't know whether other DB engines have similar function or not.
Update 2: Removed the unnecessary sorting.
Two possible problems:
This won't work if your list isn't sorted
You aren't doing anything with ob.getTerminationReason(). I think you mean to add it to the previous object.
EDIT: Now that i see you´ve edited your question.
As your list is sorted, (by ssn I presume)
Integer currentSSN = null;
List<People> peoplelist = getSortedList();//gets sorted list from DB.
/*Uses foreach construct instead of iterators*/
for (People person:peopleList){
if (currentSSN != null && people.getSSN().equals(currentSSN)){
//same person
system.out.print(person.getReason()+" ");//writes termination reason
}
else{//person has changed. New row.
currentSSN = person.getSSN();
system.out.println(" ");//new row.
system.out.print(person.getSSN()+ " ");//writes row header.
}
}
If you don´t want to display the contents of your list, you could use it to create a MAP and then use it as shown below.
If your list is not sorted
Maybe you should try a different approach, using a Map. Here, ssn would be the key of the map, and values could be a list of People
Map<Integer,List<People>> mymap = getMap();//loads a Map from input data.
for(Integer ssn:mymap.keyset()){
dorow(ssn,mymap.get(ssn));
}
public void dorow(Integer ssn, List<People> reasons){
system.out.print(ssn+" ");
for (People people:reasons){
system.out.print(people.getTerminationReason()+" ");
}
system.out.println("-----");//row separator.
Last but not least, you should override your hashCode() and equals() method on People class.
for example
public void int hashcode(){
return 3*this.reason.hascode();
}

Categories

Resources