我有一个这样的字符串:
pet:cat::car:honda::location:Japan::food:sushi
现在:
表示键值对,::
分隔对。
我想将键值对添加到地图中。
我可以使用以下方式实现这一目标:
Map<String, String> map = new HashMap<String, String>();
String test = "pet:cat::car:honda::location:Japan::food:sushi";
String[] test1 = test.split("::");
for (String s : test1) {
String[] t = s.split(":");
map.put(t[0], t[1]);
}
for (String s : map.keySet()) {
System.out.println(s + " is " + map.get(s));
}
但这样做有效吗?
我觉得代码效率低下,因为我使用了2个String[]
个对象并且两次调用split
函数。
另外,我使用t[0]
和t[1]
,如果没有值,可能会抛出ArrayIndexOutOfBoundsException
。
答案 0 :(得分:15)
使用Guava库它是一个单行程序:
String test = "pet:cat::car:honda::location:Japan::food:sushi";
Map<String, String> map = Splitter.on( "::" ).withKeyValueSeparator( ':' ).split( test );
System.out.println(map);
输出:
{pet=cat, car=honda, location=Japan, food=sushi}
这也可能比JDK String.split
更快,因为它不会为"::"
创建正则表达式。
更新它甚至可以正确处理评论中的角落案例:
String test = "pet:cat::car:honda::location:Japan::food:sushi:::cool";
Map<String, String> map = Splitter.on( "::" ).withKeyValueSeparator( ':' ).split( test );
System.out.println(map);
输出结果为:
{pet=cat, car=honda, location=Japan, food=sushi, =cool}
答案 1 :(得分:13)
您可以使用以下代码单独调用split()和String上的单个传递。但它当然假设String首先是有效的:
Map<String, String> map = new HashMap<String, String>();
String test = "pet:cat::car:honda::location:Japan::food:sushi";
// split on ':' and on '::'
String[] parts = test.split("::?");
for (int i = 0; i < parts.length; i += 2) {
map.put(parts[i], parts[i + 1]);
}
for (String s : map.keySet()) {
System.out.println(s + " is " + map.get(s));
}
以上可能比你的解决方案更有效率,但如果你发现你的代码更清晰,那就保留它,因为这样的优化几乎没有机会对性能产生重大影响,除非你做了数百万次。无论如何,如果它如此重要,那么你应该测量和比较。
编辑:
对于那些想知道上面代码中::?
含义的人:String.split()将正则表达式作为参数。分隔符是与正则表达式匹配的子字符串。 ::?
是正则表达式,表示:1个冒号,后跟0或1个冒号。因此,它允许将::
和:
视为分隔符。
答案 2 :(得分:2)
你的解决方案确实效率低下。
给你解析字符串的人也有点像小丑。存在行业标准序列化格式,如JSON或XML,其中存在快速,有效的分析。发明方形轮从来都不是一个好主意。
第一个问题:你关心吗?它是否足够慢以至于阻碍了应用程序的性能?它很可能没有,但只有一种方法可以找到答案。对您的代码进行基准测试。
尽管如此,存在更有效的解决方案。以下是一个例子
public static void main (String[] args) throws java.lang.Exception
{
String test = "pet:cat::car:honda::location:Japan::food:sushi";
boolean stateiskey = true;
Map<String, String> map = new HashMap<>();
int keystart = 0;
int keyend = 0;
int valuestart = 0;
int valueend = 0;
for(int i = 0; i < test.length(); i++){
char nextchar = test.charAt(i);
if (stateiskey) {
if (nextchar == ':') {
keyend = i;
stateiskey = false;
valuestart = i + 1;
}
} else {
if (i == test.length() - 1 || (nextchar == ':' && test.charAt(i + 1) == ':')) {
valueend = i;
if (i + 1 == test.length()) valueend += 1; //compensate one for the end of the string
String key = test.substring(keystart, keyend);
String value = test.substring(valuestart, valueend);
keystart = i + 2;
map.put(key, value);
i++;
stateiskey = true;
}
}
}
System.out.println(map);
}
此解决方案是一个只有两种状态的有限状态机。它只查看每个字符两次,一次是在测试边界时,一次是将它复制到地图中的新字符串。这是最低金额。
它不会创建不需要的对象,如字符串构建器,字符串或数组,这会使收集压力降低。
它保持良好的地方。下一个字符可能总是在缓存中,因此查找很便宜。
它的成本很高,但可能不值得:
https://ideone.com/8T7twy的一个快速而肮脏的基准测试告诉我,对于这个字符串,这种方法的速度大约快4倍。对于较长的琴弦,差异可能会更大一些。
但你的版本在重复100.000次时仍然只有415毫秒,其中这个是99毫秒。
答案 3 :(得分:1)
尝试此代码-参见注释以获取解释:
HashMap<String,String> hmap = new HashMap<>();
String str="abc:1::xyz:2::jkl:3";
String straraay[]= str.split("::?");
for(int i=0;i<straraay.length;i+=2) {
hmap.put(straraay[i],straraay[i+1]);
}
for(String s:straraay){
System.out.println(hmap.values()); //for Values only
System.out.println(hmap.keySet()); //for keys only if you want to more clear
}
答案 4 :(得分:0)
我不知道这是最好的方法,但我认为这是另一种不使用拆分方法做同样事情的方法
Map<String, String> map = new HashMap<String, String>();
String test = "pet:cat::car:honda::location:Japan::food:sushi";
String[] test1 = test.replaceAll("::",":").split(":");
for(int i=0;i<test1.length;i=i+2)
{
map.put(test1[i], test1[i+1]);
}
for (String s : map.keySet()) {
System.out.println(s + " is " + map.get(s));
}
希望它会有所帮助:)
答案 5 :(得分:0)
这可能有用。 * utm_source = test_source&utm_medium = test_medium&utm_term = test_term& utm_content = test_content&utm_campaign = test_name&referral_code = DASDASDAS
String str[] = referrerString.split("&");
HashMap<String,String> stringStringHashMap= new HashMap<>();
List<String> al;
al = Arrays.asList(str);
String[] strkey ;
for (String s : al) {
strkey= s.split("=");
stringStringHashMap.put(strkey[0],strkey[1]);
}
for (String s : stringStringHashMap.keySet()) {
System.out.println(s + " is " + stringStringHashMap.get(s));
}
答案 6 :(得分:-1)
你的节目绝对没问题。
只是因为你要求更优的代码。
我通过使用少量变量而不是将数组存储在其中来减少你的记忆。
看看你的字符串,它遵循一个模式。
key : value :: key : value ::....
我们可以从中做些什么?
获取密钥,直到:
,一旦达到:
获取值,直到达到'::'。
package qwerty7;
import java.util.HashMap;
public class Demo {
public static void main(String ar[])
{
StringBuilder s = new StringBuilder("pet:cat::car:honda::location:Japan::food:sushi");
boolean isKey = true;
String key = "", value = "";
HashMap<String, String> hm = new HashMap();
for(int i = 0; i < s.length(); i++)
{
char ch = s.charAt(i);
char nextChar = s.charAt(i+1);
if(ch == ':' && nextChar != ':')
{
isKey = false;
continue;
}
else if(ch == ':' && nextChar == ':')
{
hm.put(key, value);
isKey = true;
key = "";
value = "";
i+=1;
continue;
}
if(isKey)
{
key += ch;
}
else
{
value += ch;
}
if(i == s.length() - 1)
{
hm.put(key, value);
}
}
for (String x : hm.keySet()) {
System.out.println(x + " is " + hm.get(x));
}
}
}
这样做不会在每次分割时占用很多迭代次数。
不占用太多记忆。
时间复杂度O(n)
<强>输出:强>
car is honda
location is Japan
pet is cat
food is sushi