Java中“分组依据”和聚合值的最佳数据结构?

时间:2015-05-04 10:39:54

标签: java arraylist data-structures group-by

我创建了一个Array类型的ArrayList,如下所示,

ArrayList<Object[]> csvArray = new ArrayList<Object[]>();

如您所见,ArrayList的每个元素都是{Country,City,Name,Age}这样的数组。

现在我想在国家城市(合并)上做一个“分组”,然后选择每个国家+城市的人口的平均年龄

我可以知道实现这一目标的最简单方法是什么?或者你们有建议使用比ArrayList更好的数据结构来实现这个“分组依据”和聚合要求吗?

非常感谢您的回答。

8 个答案:

答案 0 :(得分:3)

您将在Java 8中获得很多选项。

示例

List<Integer> myList = new ArrayList<Integer>();

如果您可以使用Java 8并且没有使用数据结构的具体原因,则可以阅读以下教程

http://java.dzone.com/articles/java-8-group-collections

答案 1 :(得分:1)

您可以使用Java 8流和Collectors.groupingBy。例如:

final List<Object[]> data = new ArrayList<>();
data.add(new Object[]{"NL", "Rotterdam", "Kees", 38});
data.add(new Object[]{"NL", "Rotterdam", "Peter", 54});
data.add(new Object[]{"NL", "Amsterdam", "Suzanne", 51});
data.add(new Object[]{"NL", "Rotterdam", "Tom", 17});

final Map<String, List<Object[]>> map = data.stream().collect(
        Collectors.groupingBy(row -> row[0].toString() + ":" + row[1].toString()));

for (final Map.Entry<String, List<Object[]>> entry : map.entrySet()) {
    final double average = entry.getValue().stream()
                                .mapToInt(row -> (int) row[3]).average().getAsDouble();
    System.out.println("Average age for " + entry.getKey() + " is " + average);
}

答案 2 :(得分:1)

您可以查看@ duffy356推荐的收藏品。我可以为您提供与java.utils

相关的标准解决方案

我使用普通Map<Key,Value>并具体为HashMap 对于钥匙,我可以看到,你需要和国家和城市有关的额外普通物体。重点是创建一个有效的equals(Object) : boolean方法。我使用Eclipse-auto发生器;对我来说它给了我以下内容:

class CountryCityKey {
 // package visibility
 String country;
 String city;

@Override
public int hashCode() {
  final int prime = 31;
  int result = 1;
  result = prime * result + ((country == null) ? 0 : country.hashCode());
  result = prime * result + ((region == null) ? 0 : region.hashCode());
  return result;
}

@Override
public boolean equals(Object obj) {
  if (this == obj)
    return true;
  if (obj == null)
    return false;
  if (getClass() != obj.getClass())
    return false;
  CountryCityKey other = (CountryCityKey) obj;
  if (country == null) {
    if (other.country != null)
      return false;
  } else if (!country.equals(other.country))
    return false;
  if (region == null) {
    if (other.region != null)
      return false;
  } else if (!region.equals(other.region))
    return false;
  return true;
}

}

现在我们可以在HashMap<CountryCityKey, MySuperObject>

中对组或对象进行分组

该代码可以是:

Map<CountryCityKey, List<MySuperObject>> group(List<MySu0perObject> list) {
  Map<CountryCityKey, MySuperObject> response = new HashMap<>(list.size());  
  for (MySuperObject o : list) {
     CountryCityKey key = o.getKey(); // I consider this done, so simply
     List<MySuperObject> l;
     if (response.containsKey(key)) {
        l = response.get(key);
     } else {
        l = new ArrayList<MySuperObject>();
     }
     l.add(o);
     response.put(key, l);
  }
  return response;
}

你有它:)

答案 3 :(得分:0)

你可以使用magicwerk.org(http://www.magicwerk.org/page-collections-overview.html

的布朗尼集合库

他们提供符合您要求的密钥列表。(http://www.magicwerk.org/page-collections-examples.html

答案 4 :(得分:0)

我建议另外一步。您从Object []中的CSV收集数据。如果将数据包装到包含这些数据的类中,java8集合将很容易为您提供帮助。 (也没有,但它更具可读性和可理解性)

这是一个示例 - 它引入了一个类Information,其中包含您的给定数据(国家,城市,名称,年龄)。该类有一个构造函数,通过给定的Object[]数组初始化这些字段,这可能有助于您这样做 - 但是:字段必须固定(这通常用于CSV):

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class CSVExample {

  public static void main(String[] args) {
    ArrayList<Information> csvArray = new ArrayList<>();

    csvArray.add(new Information(new Object[] {"France", "Paris", "Pierre", 34}));
    csvArray.add(new Information(new Object[] {"France", "Paris", "Madeleine", 26}));
    csvArray.add(new Information(new Object[] {"France", "Toulouse", "Sam", 34}));
    csvArray.add(new Information(new Object[] {"Italy", "Rom", "Paul", 44}));

// combining country and city with whitespace delimiter to use it as the map key
    Map<String, List<Information>> collect = csvArray.stream().collect(Collectors.groupingBy(s -> (s.getCountry() + " " + s.getCity())));
//for each key (country and city) print the key and the average age
    collect.forEach((k, v) -> System.out.println(k + " " + v.stream().collect(Collectors.averagingInt(Information::getAge))));
  }
}

class Information {
  private String country;
  private String city;
  private String name;
  private int age;

  public Information(Object[] information) {
    this.country = (String) information[0];
    this.city = (String) information[1];
    this.name = (String) information[2];
    this.age = (Integer) information[3];

  }

  public Information(String country, String city, String name, int age) {
    super();
    this.country = country;
    this.city = city;
    this.name = name;
    this.age = age;
  }

  public String getCountry() {
    return country;
  }

  public String getCity() {
    return city;
  }

  public String getName() {
    return name;
  }

  public int getAge() {
    return age;
  }

  @Override
  public String toString() {
    return "Information [country=" + country + ", city=" + city + ", name=" + name + ", age=" + age + "]";
  }

}

主要显示您问题的简单输出。

答案 5 :(得分:0)

在java 8中,通过使用收集器简化了基于一个或多个属性的值对集合中的对象进行分组的想法。

首先,我建议您添加一个新课程,如下所示

                ListView ProuctListView = new ListView();

                for (int i = 0; i < GetProductByCategoryResultObject.Products.Count;i++ )
                {
                    ProductsListing ProductsListingObject = new ProductsListing();

                    ProductsListingObject.ProductsListingLabel.Text = GetProductByCategoryResultObject.Products[i].ProductName;

                    if (GetProductByCategoryResultObject.Products[i].ProductThumbnail != null || GetProductByCategoryResultObject.Products[i].ProductThumbnail != "")
                    {
                        ProductsListingObject.ProductsListingImage.Source = new BitmapImage(new Uri(GetProductByCategoryResultObject.Products[i].ProductThumbnail,UriKind.Absolute));

                    }

                    ProuctListView.Items.Add(ProductsListingObject);

                }

                //Grid GridObject = new Grid();
                //GridObject.Children.Add(ProuctListView);
                (MainPagePivot.SelectedItem as PivotItem).Content = null;

                //(MainPagePivot.SelectedItem as PivotItem).Content = GridObject;
                (MainPagePivot.SelectedItem as PivotItem).Content = ProuctListView;

设置class Info { private String country; private String city; private String name; private int age; public Info(String country,String city,String name,int age){ this.country=country; this.city=city; this.name=name; this.age=age; } public String toString() { return "("+country+","+city+","+name+","+age+")"; } // getters and setters }

infos

按国家+城市分组:

   ArrayList<Info> infos  =new  ArrayList();


   infos.add(new Info("USA", "Florida", "John", 26));
   infos.add(new Info("USA", "Florida", "James", 18));
   infos.add(new Info("USA", "California", "Alan", 30));

<强>输出

  Map<String, Map<String, List<Info>>> 
           groupByCountryAndCity = infos.
             stream().
               collect(
                    Collectors.
                        groupingBy(
                            Info::getCountry,
                            Collectors.
                                groupingBy(
                                     Info::getCity     
                                          )
                                   )
                     );


    System.out.println(groupByCountryAndCity.get("USA").get("California"));

每个国家+城市的平均人口年龄:

[(USA,California,James,18), (USA,California,Alan,30)]

<强>输出:

    Map<String, Map<String, Double>> 
    averageAgeByCountryAndCity = infos.
         stream().
           collect(
             Collectors.
                 groupingBy(
                    Info::getCountry,
                     Collectors.
                         groupingBy(
                             Info::getCity,
                             Collectors.averagingDouble(Info::getAge)
                                   )
                            )
              );

     System.out.println(averageAgeByCountryAndCity.get("USA").get("Florida"));

答案 6 :(得分:0)

/* category , list of cars*/
  

请使用以下代码:我已从我的示例应用中粘贴了它!快乐编码。

                            Map<String, List<JmCarDistance>> map = new HashMap<String, List<JmCarDistance>>();

                            for (JmCarDistance jmCarDistance : carDistanceArrayList) {
                                String key  = jmCarDistance.cartype;
                                if(map.containsKey(key)){
                                    List<JmCarDistance> list = map.get(key);
                                    list.add(jmCarDistance);

                                }else{
                                    List<JmCarDistance> list = new ArrayList<JmCarDistance>();
                                    list.add(jmCarDistance);
                                    map.put(key, list);
                                }

                            }

答案 7 :(得分:0)

最佳数据结构是Map

元组是关键,即您按列分组。 列表用于存储行数据。

一旦数据具有此结构,就可以遍历每个键,并对数据子集执行汇总。