我有故事列表。我想使用唯一的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);
});
}
}
答案 0 :(得分:4)
一个多图每个键只能存储多个值,但是您想要的是将这些多个值组合在一起,以便获得一个具有相同ID和标题以及一组关键字和定位信息的元素。因此,最好使用类似MultiStory
的东西或已经包含这些集合的Story
。
我建议您使用适当的对象而不是仅使用地图,而对于地图和Java 8 lambda,您可以使用compute()
等来构建包含集合的地图,并合并不包含地图的地图。
这是您如何使用地图的示例。请注意,这是非常糟糕的样式,下面将使用适当的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 );
});
如您所见,不需要强制转换,并且很明显有哪些可用字段(尽管不一定要填充),这使代码和点错误的推理变得更加容易(编译器可以在这里提供很多帮助,而这是不可能的)在使用地图的示例中为。
答案 1 :(得分:2)
这是一个使用类表示故事和标签的解决方案:
public static void main(String[] args) {
TagsCollector app = new TagsCollector();
app.go();
}
private void go() {
List<Story> stories = createStories();
System.out.println(stories);
Map<Long, Tags> tagsById = collectTags(stories);
tagsById.forEach((aLong, tags) -> System.out.println(tags));
}
private List<Story> createStories() {
return Arrays.asList(
new Story(1, "Onboarding", "new joinee", "finance"),
new Story(1, "Onboarding", "training", "HR")
);
}
private Map<Long, Tags> collectTags(List<Story> stories) {
Map<Long, Tags> tagsById = new HashMap<>();
stories.forEach(s -> {
Tags tags = tagsById.computeIfAbsent(s.id, v -> new Tags(s));
tags.getKeywords().add(s.getKeyword());
tags.getTargetings().add(s.getTargeting());
});
return tagsById;
}
用于表示故事的类:
public class Story {
private final long id;
private final String title;
private final String keyword;
private final String targeting;
public Story(long id, String title, String keyword, String targeting) {
this.id = id;
this.title = title;
this.keyword = keyword;
this.targeting = targeting;
}
public long getId() {
return id;
}
public String getTitle() {
return title;
}
public String getKeyword() {
return keyword;
}
public String getTargeting() {
return targeting;
}
@Override
public String toString() {
return String.format("Story %s, title=%s, keyword=%s, targeting=%s", id, title, keyword, targeting);
}
}
用于表示标记的类:
public class Tags {
private final long id;
private final String title;
private final List<String> keywords = new ArrayList<>();
private final List<String> targetings = new ArrayList<>();
Tags(Story story) {
this.id = story.id;
this.title = story.title;
}
public List<String> getKeywords() {
return keywords;
}
public List<String> getTargetings() {
return targetings;
}
@Override
public String toString() {
return String.format("Tags for id %s, title:%s: keywords=%s, targetings=%s", id, title, keywords, targetings);
}
}
输出
[Story 1, title=Onboarding, keyword=new joinee, targeting=finance, Story 1, title=Onboarding, keyword=training, targeting=HR]
Tags for id 1, title:Onboarding: keywords=[new joinee, training], targetings=[finance, HR]
答案 2 :(得分:1)
是的,您可以使用Multimap来实现。首先,我将为Story定义一个pojo,以使情况更清楚:
public class Story {
private int id;
private String title;
private String keyword;
private String targeting;
//getters setters
}
第二,您需要使用哈希码和等号定义键。
public static class StoryKey {
private final int id;
private final String title;
public StoryKey(int id, String title) {
this.id = id;
this.title = title;
}
//getters
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
StoryKey storyKey = (StoryKey) o;
if (id != storyKey.id) return false;
return title != null ? title.equals(storyKey.title) : storyKey.title == null;
}
@Override
public int hashCode() {
int result = id;
result = 31 * result + (title != null ? title.hashCode() : 0);
return result;
}
代码如下:
ArrayListMultimap<StoryKey, Story> multiMap = ArrayListMultimap.create();
List<Story> stories = new ArrayList();
Story story1 = new Story();
story1.setId(1);
story1.setTitle("Onboarding");
story1.setKeyword("training");
story1.setTargeting("HR");
Story story2 = new Story();
story2.setId(1);
story2.setTitle("Onboarding");
story2.setKeyword("new joinee,");
story2.setTargeting("finance");
stories.add(story1);
stories.add(story2);
System.out.println(stories);
stories.
forEach((story) -> {
multiMap.put(new StoryKey(story.getId(), story.getTitle()), story);
});
multiMap.keys().forEach(key ->
System.out.println(
"id =" + key.getId() +
" title =" + key.getTitle()+
"keyword =" + multiMap.get(key).stream().map(story->story.getKeyword()).collect(Collectors.toList()).toString()+
"targeting ="+ multiMap.get(key).stream().map(story->story.getTargeting()).collect(Collectors.toList()).toString())
);