将字符串拆分为键值对
Split string into key-value pairs
我有这样的字符串:
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
。
您可以使用以下代码调用一次 split() 并传递一次字符串。但它当然首先假定字符串是有效的:
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 个冒号。因此,它允许将 ::
和 :
视为分隔符。
我不知道这是不是最好的方法,但我认为这是另一种不使用拆分方法来做同样事情的方法
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));
}
希望对您有所帮助:)
你的程序绝对没问题。
只是因为您要求更优化的代码。
我通过使用少量变量而不是使用数组并存储在其中来减少你的内存。
看看你的字符串,它遵循一种模式。
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));
}
}
}
Doing so doesn't take up much iterations on splitting each time.
Doesn't take up much memory.
Time complexity O(n)
输出:
car is honda
location is Japan
pet is cat
food is sushi
使用 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}
你的方案确实有些低效。
给你解析字符串的人也是个小丑。有行业标准的序列化格式,如 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);
}
这个解决方案是一个只有两个状态的有限状态机。它只查看每个字符两次,一次是在测试边界时,一次是在将其复制到地图中的新字符串时。这是最低金额。
它不会创建不需要的对象,例如 stringbuilder、字符串或数组,这样可以保持较低的收集压力。
它保持良好的地方性。下一个字符可能总是在缓存中,因此查找很便宜。
它付出了巨大的代价,但可能不值得:
- 它要复杂得多,也不那么明显
- 有各种各样的活动部件
- 当您的字符串采用非预期格式时,调试起来会更加困难
- 你的同事会讨厌你
- 非要debug什么的你会恨死你的
值得吗?可能是。您需要以多快的速度准确解析该字符串?
https://ideone.com/8T7twy 的一个快速而肮脏的基准测试告诉我,对于这个字符串,这个方法大约快 4 倍。对于更长的字符串,差异可能会更大。
但是你的版本仍然只有 415 毫秒重复 100.000 次,而这个是 99 毫秒。
尝试此代码 - 请参阅注释以获取解释:
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
}
这可能会有用。
*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));
}
我有这样的字符串:
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
。
您可以使用以下代码调用一次 split() 并传递一次字符串。但它当然首先假定字符串是有效的:
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 个冒号。因此,它允许将 ::
和 :
视为分隔符。
我不知道这是不是最好的方法,但我认为这是另一种不使用拆分方法来做同样事情的方法
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));
}
希望对您有所帮助:)
你的程序绝对没问题。
只是因为您要求更优化的代码。
我通过使用少量变量而不是使用数组并存储在其中来减少你的内存。
看看你的字符串,它遵循一种模式。
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));
}
}
}
Doing so doesn't take up much iterations on splitting each time.
Doesn't take up much memory.
Time complexity O(n)
输出:
car is honda
location is Japan
pet is cat
food is sushi
使用 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}
你的方案确实有些低效。
给你解析字符串的人也是个小丑。有行业标准的序列化格式,如 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);
}
这个解决方案是一个只有两个状态的有限状态机。它只查看每个字符两次,一次是在测试边界时,一次是在将其复制到地图中的新字符串时。这是最低金额。
它不会创建不需要的对象,例如 stringbuilder、字符串或数组,这样可以保持较低的收集压力。
它保持良好的地方性。下一个字符可能总是在缓存中,因此查找很便宜。
它付出了巨大的代价,但可能不值得:
- 它要复杂得多,也不那么明显
- 有各种各样的活动部件
- 当您的字符串采用非预期格式时,调试起来会更加困难
- 你的同事会讨厌你
- 非要debug什么的你会恨死你的
值得吗?可能是。您需要以多快的速度准确解析该字符串?
https://ideone.com/8T7twy 的一个快速而肮脏的基准测试告诉我,对于这个字符串,这个方法大约快 4 倍。对于更长的字符串,差异可能会更大。
但是你的版本仍然只有 415 毫秒重复 100.000 次,而这个是 99 毫秒。
尝试此代码 - 请参阅注释以获取解释:
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
}
这可能会有用。 *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));
}