将字符串拆分为键值对
我有一个像这样的字符串:
pet:cat::car:honda::location:Japan::food:sushi
Now :
表示键值对,而::
分隔对。 我想将键值对添加到地图中。
我可以使用以下方法实现:
Map map = new HashMap(); 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
。
您可以使用以下代码单独调用split()和String上的单个传递。 但它当然假设String首先是有效的:
Map map = new HashMap(); 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个冒号。 因此它允许考虑::
和:
作为分隔符。
使用Guava库它是一个单行:
String test = "pet:cat::car:honda::location:Japan::food:sushi"; Map 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 map = Splitter.on( "::" ).withKeyValueSeparator( ':' ).split( test ); System.out.println(map);
输出是:
{pet=cat, car=honda, location=Japan, food=sushi, =cool}
您的解决方案确实效率低下。
给你解析字符串的人也有点像小丑。 存在行业标准序列化格式,如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 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毫秒。
我不知道这是最好的方法,但我认为这是另一种做同样事情而不使用拆分方法两次的方法
Map map = new HashMap(); String test = "pet:cat::car:honda::location:Japan::food:sushi"; String[] test1 = test.replaceAll("::",":").split(":"); for(int i=0;i
希望它会有所帮助:)
你的程序绝对没问题。
只是因为你要求更优的代码。
我通过使用少量变量而不是将数组存储在其中来减少您的记忆。
看看你的字符串,它遵循一个模式。
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 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
HashMap hmap = new HashMap<>(); String str="abc:1::xyz:2::jkl:3"; String straraay[]= str.split("::?"); for(int i=0;i
}