java - 如何使用 MultiMap 通过唯一属性收集 List<Map> 的属性?

标签 java list

我有故事列表。使用独特的 property(id) 我想收集关键字和定位作为值列表。我可以用 MultiMap 做到这一点吗?或者还有其他图书馆吗?

[{
    id = 1,
    title = Onboarding,
    keyword = new joinee,
    targeting = finance
}, {
    id = 1,
    title = Onboarding,
    keyword = training,
    targeting = HR
}]

期望的输出必须是这样的:

{
    id = 1,
    title = Onboarding,
    keyword = [new joinee,training], //may be keywords - plural
    targeting = [HR,finance]
} 

我试过的代码示例如下:

package prac;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class JavaPrac {
    public static void main(String[] args) {
        Multimap<Integer, Map> multiMap = ArrayListMultimap.create();

        List<Map> stories=new ArrayList();

        Map story1=new HashMap();
        story1.put("id", 1);
        story1.put("title", "Onboarding");
        story1.put("keyword","new joinee");
        story1.put("targeting","finance");

        Map story2=new HashMap();
        story2.put("id", 1);
        story2.put("title", "Onboarding");
        story2.put("keyword","training");
        story2.put("targeting","HR");

        stories.add(story1);
        stories.add(story2);

        System.out.println(stories);

        stories.forEach((story) -> {
            multiMap.put((Integer) story.get("id"), story);
        });
    }
}

最佳答案

multimap 只能为每个键存储多个值,但您想要的是组合这些多个值,以便获得一个具有相同 ID 和标题的元素以及一组关键字和定位信息。因此,最好要么拥有类似 MultiStory 的东西,要么已经拥有包含这些集合的 Story

我建议使用适当的对象而不仅仅是 map ,但是对于 map 和 Java 8 lambda,您可以使用 compute() 等来构建包含集合的 map 并组合不包含集合的 map 。

以下是您如何使用 map 执行此操作的示例。请注意,这是非常糟糕的风格,下面是一个使用适当 pojos 的示例:

免责声明:基于 OP 代码的示例,不推荐(阅读上面的文字)

//Problem 1: we don't know the type of the values, i.e. we could put anything for "id" etc.
Map<String, Object> story1=new HashMap<>();
story1.put("id", 1);
story1.put("title", "Onboarding");
story1.put("keyword","new joinee");
story1.put("targeting","finance");

Map<String, Object> story2=new HashMap<>();
story2.put("id", 1);
story2.put("title", "Onboarding");
story2.put("keyword","training");
story2.put("targeting","HR");

List<Map<String, Object>> stories=new ArrayList<>();

stories.add(story1);
stories.add(story2);

Map<Integer, Map<String, Object>> combined = new HashMap<>();

stories.forEach((story) -> {
  //Problem 2: because we don't know the type of the values we need a lot of nasty casts
  Map<String, Object> combinedStory = combined.computeIfAbsent( (Integer)story.get( "id" ), k -> new HashMap<String, Object>() );
  combinedStory.put("id", story.get( "id" ) );
  combinedStory.put("title", story.get( "title" ) );

  //Problem 3: the combined map would look a lot like your "story" maps but would contain different types
  ((List<String>)combinedStory.computeIfAbsent( "keyword", v -> new List<String>() )).add( (String)story.get("keyword") );
  ((List<String>)combinedStory.computeIfAbsent( "targeting", v -> new List<String>() )).add( (String)story.get("targeting") );
});

使用 POJO

这是一个大大简化的示例,说明如何使用适当的 Java 对象 (POJO) 来完成此操作。请注意,这些是为了尽可能类似于您的代码,还有很多其他问题,但在这里解决这些问题太多了,设计得更好的代码会更大,而且可能更难理解——毕竟这只是意味着向您展示不同之处。

首先让我们定义我们的类(为简单起见,我公开了这些字段,您通常不会那样做):

class Story {
  public final int id;
  public String title;
  public String keyword;
  public String targeting;

  public Story(int storyId) {
    id = storyId ;
  }
}

class MultiStory {
  public final int id;
  public String title;
  public Set<String> keywords = new HashSet<>();
  public Set<String> targetingInfo = new HashSet<>();

  public MultiStory( int storyId ) {
    id = storyId ;
  }
}

然后让我们重申一下上面的代码:

Story story1=new Story( 1 );
story1.title = "Onboarding";
story1.keyword = "new joinee";
story1.targeting = "finance";

Story story2=new Story( 1 );
story2.title = "Onboarding";
story2.keyword = "training";
story2.targeting = "HR";

List<Story> stories=new ArrayList<>();

stories.add(story1);
stories.add(story2);

Map<Integer, MultiStory> combined = new HashMap<>();

stories.forEach((story) -> {
  MultiStory multiStory = combined.computeIfAbsent( story.id, v -> new MultiStory( story.id ) );
  multiStory.title = story.title;
  multiStory.keywords.add( story.keyword );
  multiStory.targetingInfo.add( story.targeting );
});

如您所见,不需要转换,并且很清楚哪些字段可用(尽管不一定填写),这使得对代码进行推理和发现错误变得更加容易(编译器在这里可以提供很多帮助,但它不能) t 在使用 map 的示例中)。

关于java - 如何使用 MultiMap 通过唯一属性收集 List<Map> 的属性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53408742/

相关文章:

c - 为什么尝试添加 count 和 printf 时会出现段错误?

Java持久化: @ManyToMany Project to List<Projects>

java - 不确定为什么会收到此 "cannot find symbol"错误

python - 检索 Pandas 数据帧行,其列(一)值连续等于列表的值

java - MethodHandles 还是 LambdaMetafactory?

JavaFX (2.2) 将字符串从内存加载到 WebView 中

java - 在 Java 中克隆

java - Java 需要的 FileSet 包/类

list - 在 Elixir 中有效压缩不等长列表

java - 使用eclipse在tomcat上部署后找不到页面