【问题标题】:What would be a cleaner way to cluster ArrayList() based on one column data?基于一列数据对 ArrayList() 进行聚类的更简洁的方法是什么?
【发布时间】:2019-09-28 06:44:56
【问题描述】:

假设我有以下列表

 full_list

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

有了这个单一列表,我想创建一个基于列 ID 的分组列表,如下所示

 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

我试图用Arraylist<ArrayList<CustomObject>> 来做这件事。但它增加了代码的复杂性。我做错了吗?有没有更清洁的方法来做到这一点?

PS:数据传入不固定。我无法使用条件明确定义列表(即 if(id==1)、if(id==2) 等)。这应根据传入的数据动态完成。

【问题讨论】:

  • 使用列表映射,id 是映射的键,映射的值是该键的对象列表
  • 为此您不能使用arraylist。但是,您可以使用列表映射。您的地图将类似于 Map> myMap = new LinkedHashMap>().
  • @MohinuddinLuhar 我必须使用 ArrayList,因为我正在将数据库(结果集)中的数据填充到数组列表中。我们是否可以将结果集数据直接填充到 Map 中?
  • 您必须以某种数据结构获取数据。那是什么?
  • @SSP 数据是来自数据库的结果集,例如 (int, date, string, string, string, int),我只想在第一个 int 上分组。

标签: java arraylist


【解决方案1】:

正如您所说,如果您使用列表执行此操作会更复杂。这个逻辑可以通过使用 Map 和 List 来简化。使用 Map 和 List 实现此目的的示例代码如下

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

在上面的代码中,我在数据库中创建了与您相同的表。并且数据现在被动态添加到地图中。无论您在数据库中拥有什么 id 都将成为地图的键,而针对该 id 的值将成为值列表。键可以是任何整数,您可以将它们进一步映射到特定列表。

创建表和插入数据的查询如下

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');

【讨论】:

    【解决方案2】:

    您需要使用Map,它将ID 作为其键,并将值作为对象的List。假设你有以下类:

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

    您的结果应该是Map&lt;Integer, List&lt;Item&gt;&gt; 类型。实现此目的的一种方法是使用Collectors.groupingBy。例如:

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

    这将创建一个按Item 类的id 属性分组的地图。

    【讨论】:

    • 这个解决方案很有趣。我试过了, Map m = itemslist.stream().collect(Collectors.groupingBy(ShipmentItemsModel::getLrid)) 现在如何获取分组?
    • @Sushant 这将创建一个从 ID 到数组列表的映射,根据需要使用值。
    • 这将创建一个从 ID 到 arraylist 的映射?你的意思是它会根据id向itemlist添加地图?请指导我如何从这些数组列表中获取项目。我想我已经接近解决方案了。对不起,我在地图和收藏方面很弱。
    • @Sushant 我认为您最好通过教程来尝试理解它,从长远来看,这将为您提供更好的服务。尽你最大的努力去理解它,如果你失败了,我会很乐意帮助你。
    • 感谢您的代码。它节省了 20 行排序代码。
    【解决方案3】:

    另一个快速解决方案

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

    【讨论】:

      【解决方案4】:

      感谢大家的回答。正如@Mauron 建议的那样,我使用了Collectors.groupingby,它实际上节省了 20 行排序代码。 经过一番研究,我发现了如何列出地图中的所有键 here

      这就是我一直在寻找的解决方案

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

      所以最终的输出会是这样的

       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
      

      感谢所有答案。再次感谢大家。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-01-08
        • 1970-01-01
        • 2021-05-28
        • 1970-01-01
        • 2012-03-13
        • 2018-09-08
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多