LinkedList object add() function not updating values - java - 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()

Related

Sort List of Objects Based On Another Sorted List Object Positions In Java

I have two list objects like :
public class AttributeMaster {
public String attribute_id;
public String view_index;
...
}
List<AttributeMaster> attributes = new ArrayList<AttributeMaster>();
public class AttributeDetail {
public String attribute_id;
public String attribute_name;
...
}
List<AttributeDetail> attribute_detail = new ArrayList<AttributeDetail>();
Here, I need to sort attribute_detail list based on list attributes. List attribute is already sorted based on its view_index property.
I want to update second list based on index of attribute_master list.
If one one can help.
Collections.sort(attribute_detail,
Comparator.comparing(item -> attributes.indexOf(item)));
int start_index=0;
for(int i=0;i<attributes.size();i++) {
for(int j=0;j<attribute_detail.size();j++) {
if(attributes.get(i).getAttribute_id().equals(attribute_detail.get(j).getAttribute_id())){
AttributeDetail temp=attribute_detail.get(start_index);
attribute_detail.set(start_index, attribute_detail.get(j));
attribute_detail.set(j,temp);
start_index++;
}
}
}
Through index iterations, the code will check the object existence for both list using attribute_id. If the object present in both list, then it will sort the list of attribute_detail based on the index of attributes list.

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 - How do I add a new value to an existing key in a Hash Map. 1 key, multiple values

I am trying to create a method that, when given a key and a value, can access the map via the key and then either add or replace that specific value.
My Hash Map is created like so:
public Band(){
musicians = new HashMap<>();
}
And I can add new entries like so, with band acting as the key:
public void addMapEntry(String band, String name, String instrument, int experience){
musicians.put(band, new Musician(name, instrument, experience));
}
My new method header look like this:
public void addValue(){ }
I have tried using the put method but I can't get it work as I'd like.
I have also tried iterating through the map, but I've only ever used that method to return map objects in a list, whereas I don't want to return anything in this method. I want to be able to send it two arguments (the key and the value) and have it only replace that specific value.
I hope I have been clear in my explanation.
Java Map is single value for each key.
If you need multiple values for a single key, you should make the type a collection of the appropriate type and add your own logic for adding a new value. Your Band class should have methods to add/remove a Musician and handle the details in the private implementation.
public class Band {
private Map<String, List<Musician>> members = new HashMap<String, List<Musician>>();
public void addMusician(String key, Musician musician) {
if (this.members.containsKey(key) {
List<Musician> musicians = this.members.get(key);
if (musician != null) {
musicians.add(musician);
this.members.put(key, musicians);
}
}
}
public void removeMusician(String key, Musician musician) {
// should be clear enough from the add method.
}
}
I think the most suitable for you is to use Guava Multimap
ListMultimap<String, String> musicianMap = ArrayListMultimap.create();
Then add as many musicians to your band
musicianMap.put("Beatles", new Musician("Jhon Lennon"));
musicianMap.put("Beatles", new Musician("Paul McCartney"));
musicianMap.put("Beatles", new Musician("Ringo Starr"));
musicianMap.put("Beatles", new Musician("George Harrison"));
And you can pull them all using just key.
musicianMap.get("Beatles")
This will return a list of ["John Lenon", "Paul McCartney", "Ringo Starr"] of course these will objects of class Musician.

Any collection object to hold list of combination of more than 2 elements?

Is there a collection object or a approach to hold a combination of elements?
For instance, I need to create a list that contains the combination of the elements name, age, height and weight.
Creating an object for this is not a good idea in my case. Because the number of fields keep changing.
I need to create this list to pass to a query.
Any solution?
class MyContainer {
String someString;
int someInt;
}
List <MyContainer> myList = new List<>();
Something like that!?
I donĀ“t know exactly, what you mean by "Creating an object for this is not a good idea in my case". You could as an alternative create a List<Object> and put in whatever you have or even a List<List<Object>> if you want to have a List of a number of grouped objects.
The best approach would be to make an Object with all the possible elements in it.
class myObject {
String name;
Integer age;
Float weight;
// Etc
}
Or have a base class then have another class which extends this with additional elements
class myExtendedObject extends myObject{
String streetAddress;
String city;
// etc;
}
Then if you don't have an element set it to null... you could always build your query from the object itself by including a method to return your query, juct check if its null and not include in your query (Assuming you mean an sql style query)
public String buildQuery{
String query = "Select * from blahtable Where ";
query += (name != null)?" name = " + name : "";
// etc, or what ever your query needs to be
return query
}
Other wise you could just have a method which returns a map of your elements then you know what the type of each element is based on the key
public Map<String, Object> getElements{
Map<String, Object> myMap = new HashMap<String, Object>();
if(name != null)
myMap.put("Name", name);
// etc
return myMap
}
What about just using a Map for that and use attribute name as key (e.g. Weight )?
You can use any combination of attributes you want and it would be convenient to pass such collection to the query
Consider Enum map should you require more column names type safety

Getting duplicate values while comparing with the map

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());
}

Categories

Resources