1

Say I have a below list

 full_list

 ID     NAME
 1      Apple
 1      Banana
 2      Carrot
 1      Mango
 2      Spinach
 3      BMW
 3      Opal

With this single list, I want to create a grouped list based on column ID like below

 fruits_list              veggies_list               cars_list
 ID      NAME             ID      NAME              ID     NAME
 1       Apple            2       Carrot            3      BMW
 1       Banana           2       Spinach           3      Opal
 1       Mango

I was trying to do it with Arraylist<ArrayList<CustomObject>>. But it is adding more complexity to the code. Am I doing it wrong? Is there any cleaner way to do this?

PS: Data incoming is not fixed. I cannot define lists explicitly with conditions (i.e. if(id==1), if(id==2) etc). This shall be done dynamically based on incoming data.

Sushant
  • 165
  • 7
  • Use a map of lists, the id being the key of the map and the value of the map is the list of objects for that key – Geert-Jan Sep 28 '19 at 06:47
  • For this you cannot user arraylist. But instead you can use map of list. Your map will be like Map> myMap = new LinkedHashMap>(). – Mohinuddin Luhar Sep 28 '19 at 06:51
  • @MohinuddinLuhar I have to use ArrayList because I am populating data from database (resultset) into the arraylist. Do we have alternative to populate resultset data into Map directly? – Sushant Sep 28 '19 at 06:55
  • you must be getting data in some datastructure. what is that ? – SSP Sep 28 '19 at 06:59
  • @SSP Data is resultset from database like (int, date, string, string, string , int) and I want grouping on first `int` only. – Sushant Sep 28 '19 at 07:03

4 Answers4

5

As you had said that it will be more complex if you are doing this using an List. This logic can be simplified by using a Map and List. The sample code to achieve this using Map and List is as below

Map<Integer, List<String>> myMap = new LinkedHashMap<Integer, List<String>>();
try {
    Class.forName("com.mysql.cj.jdbc.Driver");
    Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/stackoverflow?useSSL=false",
            "root", "password");
    Statement stmt = con.createStatement();
    ResultSet rs = stmt.executeQuery("select * from `58144029`");
    while (rs.next()) {
        List<String> myList = myMap.get(rs.getInt("id")) == null ? new LinkedList<String>()
                : myMap.get(rs.getInt("id"));
        myList.add(rs.getString("name"));
        myMap.put(rs.getInt("id"), myList);
    }
    con.close();
} catch (Exception e) {
    e.printStackTrace();
}
System.out.println(myMap);
// Getting the List as per id
System.out.println(myMap.get(1));

In the code above, I had created the table in the database same as your. And the data are now added into the map dynamically. Whatever the id you have in your database will become the key of the map and the value against that id will become the list of value. Key can be any integer which you can further map them to a particular list.

Query to create table and insert data is as below

CREATE TABLE `58144029` (
  `id` int(11) NOT NULL,
  `name` varchar(64) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

INSERT INTO `58144029` (`id`, `name`) VALUES
(1, 'Apple'),
(1, 'Banana'),
(2, 'Carrot'),
(1, 'Mango'),
(2, 'Spinach'),
(3, 'BMW'),
(3, 'Opal');
Mohinuddin Luhar
  • 656
  • 10
  • 23
2

You need to use Map that will have the ID as its key, and the value as a List of your object. Suppose you have the following class:

class Item {

  private int id;
  private String name;

  public Item(int id, String name) {
    this.id = id;
    this.name = name;
  }

  public int getId() { return this.id; }
}

Your result should be of type Map<Integer, List<Item>>. One way to achieve this is by using Collectors.groupingBy. For example:

list.stream().collect(Collectors.groupingBy(Item::getId));

This will create a map, that's grouped by the id property of the Item class.

Maroun
  • 94,125
  • 30
  • 188
  • 241
  • This solution is interesting. I tried, Map m = itemslist.stream().collect(Collectors.groupingBy(ShipmentItemsModel::getLrid)) now how to fetch the grouping? – Sushant Sep 28 '19 at 07:16
  • @Sushant This will create a map from ID to array list, use the values as you wish. – Maroun Sep 28 '19 at 07:21
  • This will create a map from ID to arraylist? You mean it will add map to `itemlist` based on id? Please guide me how to fetch the items now from those arraylist. I think I am close to solution. Sorry, I am weak in maps and collections. – Sushant Sep 28 '19 at 07:29
  • @Sushant I think it's better for you to try to understand it by going through a tutorial, this will serve you better for the long run. Do your best in trying to understand it, and if you fail, I'll be more than glad to help you. – Maroun Sep 28 '19 at 07:36
  • Thanks for the code. It saved 20 lines of sorting code. – Sushant Sep 28 '19 at 10:14
0

Another Quick Solution

var arList  = [{1:'Apple'}, {1:'Banana'}, {2:'Carrot'}, {1:'Mango'}, {2:'Spinach'}, {3:'BMW'}, {3:'Opal'}]
    var sorted =[];
    arList.map(function (value, i) {
      Object.keys(value).forEach(function(key, index) {
        if(typeof sorted[key]==='undefined'){
            sorted[key] =  [value[key]];
        }else{
            sorted[key].push(value[key]);
        }
     });
    })
    sorted = sorted.filter(entry => /\S/.test(entry));

    console.log(sorted);
0

Thanks all for your answers. As @Mauron advised, I used Collectors.groupingby and it saved literally 20 lines of sorting code. After some research I found how to list all keys in map here

So here is the solution I was looking for

 //Create a grouped map using Collectors.groupingBy 
 Map m = itemslist.stream().collect(Collectors.groupingBy(ShipmentItemsModel::getLrid));
 //Make an ArrayList of keys
 ArrayList<Integer> keys = new ArrayList<>(m.keySet());
  //Use enhanced for loop (foreach) to go through each key in order to create list of items each key has.
  //(In Layman terms: It will create small lists based on keys)  
  for (int singlekey: keys) {
         ArrayList<ShipmentItemsModel> values = new ArrayList<ShipmentItemsModel>();
            values = (ArrayList<ShipmentItemsModel>) m.get(singlekey);
            for (ShipmentItemsModel sortedmodel: values) {
                System.out.println("Key/ID :"+singlekey+" and values :"+sortedmodel.getProductname());
            }
        }

So final output will be like this

 Key/ID :1 and value :Apple
 Key/ID :1 and value :Banana
 Key/ID :1 and value :Mango
 Key/ID :2 and value :Carrot
 Key/ID :2 and value :Spinach
 Key/ID :3 and value :BMW
 Key/ID :3 and value :Opal

I appreciate all the answers. Thanks all once again.

Sushant
  • 165
  • 7