I have a problem related to "dynamic ArrayLists". I have a List that contains usernames and their data. I want for every distinct username to create a single list that contains all data of this user. For example, I have an arraylist (username,tweet) that has: lefteris,"Plays ball", Kostas, "Plays basketball", lefteris, "Nice weather". And I want after that to create two lists. One list with kostas and his tweets and another with lefteris and its tweets (2 tweets). The parent arraylist may have 20 distinct usernames or more. How can I do that ?
4 回答
几个库按照函数式语言提供的方式为 Java 添加了出色的集合处理功能。一个这样的库是Google Guava。Guava 提供了一个MultiMap,可以按照你想要的方式对事物进行分组。还有许多实用方法,例如MultiMaps.index(),它通过对列表的元素应用一些函数来计算键,将列表中的项目收集到映射中。有了这样的支持,只需要几行代码和一个Function实现(任何其他语言的闭包)就可以解决您的问题:
import com.google.common.base.Function;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import java.util.Arrays;
import java.util.List;
public class Tweets {
public static final int NAME = 0;
public static final int TWEET = 1;
public static void main(String[] args) {
List<String> namesAndTweets = Arrays.asList(
"lefteris", "Plays ball",
"Kostas", "Plays basketball",
"lefteris", "Nice weather");
List<List<String>> nameTweetPairs =
Lists.partition(namesAndTweets, 2);
Multimap<String, List<String>> namesAndTweetsByName =
Multimaps.index(nameTweetPairs, get(NAME));
Multimap<String, String> tweetsByName =
Multimaps.transformValues(namesAndTweetsByName, get(TWEET));
System.out.println(tweetsByName);
}
private static Function<List<String>, String> get(final int n) {
return new Function<List<String>, String>() {
@Override
public String apply(List<String> nameAndTweet) {
return nameAndTweet.get(n);
}
};
}
}
输出:
{lefteris=[Plays ball, Nice weather], Kostas=[Plays basketball]}
更新:为了进一步解释代码,有三个基本步骤:
- 获取名称和推文混合在一起的列表,并使用Lists.partition()将其分解为 (name, tweet) 对。
- 使用 MultiMaps.index() 从对构建 MultiMap,将名称作为映射键。这为您提供了一个映射,其中映射键是名称,映射值是 (name, tweet) 对。
- 使用MultiMaps.transformValues()将地图值从 (name, tweet) 对减少为仅推文。
PS有人知道是否有一个内置函数可以做我的get()
工作吗?这似乎是一个应该提供的有用功能,但我在任何地方都找不到它。
我建议你使用 hashmap 或 hashset 代替,因为如果你需要成对存储一些东西,散列是一个完美的解决方案......
我会使用以下数据结构:
HashMap<String, ArrayList<String>>
然后,如果属性是单个项目,则您可以操作键入每个名称的“动态”属性列表:
Lefteris->("Plays ball", "Nice weather",...)
Kostas->("Plays basketball",...)
如果属性是键值对,请执行以下操作:
HashMap<String, HashMap<String, Object>>
数据看起来像:
Lefteris->(Sport->"Plays ball", Weather->"Nice",...)
Kostas->(Sport->"basketball",...)
由于您从文件中解析项目,因此您可以执行以下操作。
创建一个包含与特定用户名关联的推文的地图
Map<String,List<String>> userTweets = new HashMap<String,List<String>>();
然后,有一种方法将推文与特定用户相关联,验证它是否已添加到地图中,如果没有则添加它。
public void addTweetToUser(String user, String tweet) {
if(userTweets.containsKey(user))
userTweets.get(user).add(tweet);
else {
List<String> newUserTweets = new LinkedList<String>();
newUserTweets.add(tweet);
userTweets.put(user, newUserTweets);
}
}
另外,您可以通过创建一个UserTweet
包含以下内容的对象来改进这一点:
public class UserTweet {
private String user;
private String tweet;
//Constructor, Setters & Getters or all of them
}
然后你的addTweetToUser
方法可以有一个UserTweet
参数。
当您想知道某个用户的推文时,您只需从userTweets
地图中获取相应的列表即可。我还有删除推文和/或删除用户的方法,以防万一。