Selecting certain data from ArrayList - java

I wondering if there is anyway that if I know one part of an ArryList that I can find out the other. The problem I'm running into is my limited knowledge of java.
I have the list set up as:
spotsList = new ArrayList<HashMap<String, String>>();
The activity goes through and adds every spot(from a server) to the list in a forloop with PID and NAME as:
HashMap<String, String> map = new HashMap<String, String>();
map.put(TAG_PID, id);
map.put(TAG_NAME, name);
spotsList.add(map);
Now is there a way I can get the name if I know the PID?
Thank you in advance,
Tyler

It seems that you expect the PIDs to be unique (given a PID you can find the corresponding name). So instead of a list of maps you should probably just use one map:
Map<String, String> map = new HashMap<String, String>();
for (Spot s : spots) map.put(s.id, s.name);
Retrieving a name from the pid is then simply a matter of:
String name = map.get(pid);

You should probably use a domain class instead of a HashMap to hold that data. If you did that you could easily search a collection for a particular value.
public class Spot {
private final String pid;
private final String name;
public Spot(String pid, String name) {
this.pid = pid;
this.name = name;
}
// getters
}
You'll want to add override equals() and hashCode() also.
And then use a map instead of a list:
Map<String,Spot> spots = new HashMap<String,Spot>();
spots.put(pid, new Spot(pid, name));
Then to find one:
Spot spot = spots.get(pid);

Related

How to initialise a Map<K, Map<K,V>> on a single line

Is it possible to combine these two lines of code into one?
allPeople.put("Me", new HashMap<String, String>());
allPeople.get("Me").put("Name", "Surname");
The literal replacement of these two lines would be (in Java 8+):
allPeople.compute("Me", (k, v) -> new HashMap<>()).put("Name", "Surname");
or, in the style of Bax's answer, for pre-Java 9, you could use:
allPeople.put("Me", new HashMap<>(Collections.singletonMap("Name", "Surname")));
Starting with Java 9 there is a JDK provided Map factory
allPeople.put("Me", Map.of("Name", "Surname"));
You should probably represent a person as an object. That way you cannot call get("someKey") on a key that does not exist and your code blow up. That is the idea of object oriented programming. To encapsulate related data and functionality. Nested maps does a similar thing, but it is more error prone. For a language that does not support objects, that makes sense. But representing a person as an object allows you to better control the fields the mapping has, thus making your code more error-free.
class Person {
private String name;
private String surname;
public Person(String name, String surname) {
this.name = name;
this.surname = surname;
}
}
Then you create a map that maps names to people:
Map<String, Person> allPeople = new HashMap<>();
// Create an object that represents a person
Person me = new Person("name", "surname");
// Map the string "me" to the object me that represents me
allPeople.put("ME", me);

Best approach to have multiple key-value pairs, in a Value of an outer key

I am trying to create a dictionary type record, that holds for example key="Book name" and value= (key="price": $250, key="qty": 10). What would be the easiest way to achieve this is Java ? I have tried by creating a separate class object for they Value.
public class book_info {
int price = 0;
int qty = 0;
public void book_info(int qty, int price){
this.qty = qty;
this.price = price;
}
}
and creating a HashMap instance;
Map <String, book_info> items = new HashMap<String, book_info>();
items.put("Book1", new book_info(600, 20));
items.put("Book2", new book_info(200, 30));
items.put("Book3", new book_info(100, 50));
This works fine but is there any other alternate way by NOT using a separate class object, instead by just adding multiple key-value pairs in the initialization of HashMap like this;
Map <String, <<String, Integer>,<String, Integer>>> items = new HashMap<String, <<String, Integer>,<String, Integer>>>();
your question was probably already been answered, what your trying to do is use an object as the maping key, so instead of having [key, object] you want to have [object1, object2] and each object can be a map of which at the end will make them [[key1, value1][key2, value2]] for more details on using objects as keys see answer:
Using an instance of an object as a key in hashmap, and then access it with exactly new object?

Group objects in list by multiple fields

I have a simple object like this
public class Person {
private int id;
private int age;
private String hobby;
//getters, setters
}
I want to group a list of Person by attributes
Output should be like this
Person count/Age/Hobby
2/18/Basket
5/20/football
With a chart for more understanding
X axis : hobby repartition
Y axis : count of person distribution
Colors represents age
I managed to group by one attribute using map, but I can't figure how to group by multiples attributes
//group only by age . I want to group by hobby too
personMapGroupped = new LinkedHashMap<String, List<Person>>();
for (Person person : listPerson) {
String key = person.getAge();
if (personMapGroupped.get(key) == null) {
personMapGroupped.put(key, new ArrayList<Person>());
}
personMapGroupped.get(key).add(person);
}
Then I retrieve the groupable object like this
for (Map.Entry<String, List<Person>> entry : personMapGroupped .entrySet()) {
String key = entry.getKey();// group by age
String value = entry.getValue(); // person count
// I want to retrieve the group by hobby here too...
}
Any advice would be appreciated.
Thank you very much
Implement methods for comparing people according to the different fields. For instance, if you want to group by age, add this method to Person:
public static Comparator<Person> getAgeComparator(){
return new Comparator<Person>() {
#Override
public int compare(Person o1, Person o2) {
return o1.age-o2.age;
}
};
}
Then you can simply call: Arrays.sort(people,Person.getAgeComparator()) or use the following code to sort a Collection:
List<Person> people = new ArrayList<>();
people.sort(Person.getAgeComparator());
To sort using more than one Comparator simultaneously, you first define a Comparator for each field (e.g. one for age and one for names). Then you can combine them using a ComparatorChain. You would use the ComparatorChain as follows:
ComparatorChain chain = new ComparatorChain();
chain.addComparator(Person.getNameComparator());
chain.addComparator(Person.getAgeComparator());
You could simply combine the attributes to a key.
for (Person person : listPerson) {
String key = person.getAge() + ";" + person.getHobby();
if (!personMapGrouped.contains(key)) {
personMapGrouped.put(key, new ArrayList<Person>());
}
personMapGrouped.get(key).add(person);
}
The count of entries is easy to determine by using personMapGrouped.get("18;Football").getSize().
I'm not sure about your requirements, but I'd probably use multiple maps (Google Guava's Multimap would make that easier btw) and sets, e.g. something like this:
//I'm using a HashMultimap since order of persons doesn't seem to be relevant and I want to prevent duplicates
Multimap<Integer, Person> personsByAge = HashMultimap.create();
//I'm using the hobby name here for simplicity, it's probably better to use some enum or Hobby object
Multimap<String, Person> personsByHobby = HashMultimap.create();
//fill the maps here by looping over the persons and adding them (no need to create the value sets manually
Since I use value sets Person needs a reasonable implementation of equals() and hashCode() which might make use of the id field. This also will help in querying.
Building subsets would be quite easy:
Set<Person> age18 = personsByAge.get(18);
Set<Person> basketballers = personsByHobby.get( "basketball" );
//making use of Guava again
Set<Person> basketballersAged18 = Sets.intersection( age18, basketballers );
Note that I made use of Google Guava here but you can achieve the same with some additional manual code (e.g. using Map<String, Set<Person>> and manually creating the value sets as well as using the Set.retainAll() method).

Which collections to use?

Suppose I want to store phone numbers of persons. Which kind of collection should I use for key value pairs? And it should be helpful for searching. The name may get repeated, so there may be the same name having different phone numbers.
In case you want to use key value pair. Good choice is to use Map instead of collection.
So what should that map store ?
As far it goes for key. First thing you want to assure is that your key is unique to avoid collisions.
class Person {
long uniqueID;
String name;
String lastname;
}
So we will use the uniqueID of Person for key.
What about value ?
In this case is harder. As the single Person can have many phone numbers. But for simple task lest assume that a person can have only one phone number. Then what you look is
class PhoneNumberRegistry {
Map<Long,String> phoneRegistry = new HashMap<>();
}
Where the long is taken from person. When you deal with Maps, you should implement the hashCode and equals methods.
Then your registry could look like
class PhoneNumberRegistry {
Map<Person,String> phoneRegistry = new HashMap<>();
}
In case when you want to store more then one number for person, you will need to change the type of value in the map.
You can use Set<String> to store multiple numbers that will not duplicate. But to have full control you should introduce new type that not only store the number but also what king of that number is.
class PhoneNumberRegistry {
Map<Person,HashSet<String>> phoneRegistry = new HashMap<>();
}
But then you will have to solve various problems like, what phone number should i return ?
Your problem has different solutions. For example, I'll go with a LIST: List<Person>, where Person is a class like this:
public class Person{
private String name;
private List<String> phoneNumbers;
// ...
}
For collections searching/filtering I suggest Guava Collections2.filter method.
You should use this:
Hashtable<String, ArrayList<String>> addressbook = new Hashtable<>();
ArrayList<String> persons = new ArrayList<String>()
persons.add("Tom Butterfly");
persons.add("Maria Wanderlust");
addressbook.put("+0490301234567", persons);
addressbook.put("+0490301234560", persons);
Hashtable are save to not have empty elements, the ArrayList is fast in collect small elements. Know that multiple persons with different names may have same numbers.
Know that 2 persons can have the same number and the same Name!
String name = "Tom Butterfly";
String[] array = addressbook.keySet().toArray(new String[] {});
int firstElement = Collections.binarySearch(Arrays.asList(array),
name, new Comparator<String>() {
#Override
public int compare(String top, String bottom) {
if (addressbook.get(top).contains(bottom)) {
return 0;
}
return -1;
}
});
System.out.println("Number is " + array[firstElement]);
Maybe
List<Pair<String, String> (for one number per person)
or
List<Pair<String, String[]> (for multiple numbers per person)
will fit your needs.

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

Categories

Resources