Divide two String into substrings and pair them

2019-07-13 12:58发布

I am looking for interesting solutions for this problem :

String key = "1;2;3;4";
String value = "Value1;Value2;Value whitespace;"

Now ';' devides each value from another. The same symbol ';' devides the keys also.

Now I want to end up with :

{"1" : "Value1", "2" : "Value2", "3" : "Value whitespace", "4" : null}

Of course if the values were more then the keys then the null should be no the left side of the pair (null: "Value5").

I made a pretty complecated solution to this problem using char arrays but is one big FOR with many cases and stuff.(it is O(n)). So I am curious to see a regex or substring solution or something that not includes big loop.

EDIT: Mine solution :

private List<ExampleObject> getExampleObjects(String key , String value) {
    // s
    if (key  == null || value == null) {
        return new ArrayList<ExampleObject>();
    }

    List<ExampleObject> exampleObjects = new ArrayList<ExampleObject>();

    char[] keyToCharArray = key.toCharArray();
    char[] valueToCharArray = value.toCharArray();

    StringBuilder name = new StringBuilder();
    StringBuilder value = new StringBuilder();

    boolean nameCompleted = false;
    boolean valueCompleted = false;

    for (int i = 0, j = 0; i < keyToCharArray.length || j < valueToCharArray.length;) {
        if (!nameCompleted) {
            char a = ' ';
            try{
                 a = keyToCharArray[i];
            } catch(Exception e){
                 a = ';';
                // throw : VALES and key  not match. More key  then value
                //throw(e);
            }

            if (a == ';' ) {
                nameCompleted = true;
            } else if (!(i + 1 < keyToCharArray.length)){
                name.append(a);
                nameCompleted = true;
            }   else {
                name.append(a);

            }
            i++;
        }
        if (!valueCompleted) {

            char a = ' ';
            try{
                 a = valueToCharArray[j];
            } catch(Exception e){
                 a = ';';
                // throw : VALES and key  not match. More value then key 
                //throw(e);
            }

            if (a == ';') {
                valueCompleted = true;
            } else if(!(j + 1 < valueToCharArray.length)) {
                value.append(a);
                valueCompleted = true;
            } else {
                value.append(a);
            }
            j++;
        }
        if (nameCompleted && valueCompleted) {
            exampleObjects.add(new ExampleObject(name.toString(), value.toString()));
            name.setLength(0);
            value.setLength(0);
            nameCompleted = false;
            valueCompleted = false;
        }
    }
    return exampleObjects;
}

Where ExampleObject.class has fields key and value.

5条回答
我想做一个坏孩纸
2楼-- · 2019-07-13 13:05

Java 8:

String key = "1;2;3;4";
String value = "Value1;Value2;Value whitespace;";
String[] keys = key.split(";", -2);
String[] values = value.split(";", -2);

Map<String, String> result = IntStream.range(0, keys.length).mapToObj(i->i).collect(Collectors.toMap(i->keys[i], i-> values[i]));
result.entrySet().forEach(e->result.put(e.getKey(), e.getValue().length()==0 ? null : e.getValue()));
查看更多
Viruses.
3楼-- · 2019-07-13 13:07

Try the following: (if you want to print a String as you said)

  1. Split the two Strings into Arrays using String#split()
  2. Create counters for the value[] and the key[]
  3. Create a boolean to indicate if a key or a value gets appended
  4. Use a StringBuilder and loop through the length of the key[]
  5. Append stuff
  6. Return a new String using StringBuilder#append()

Done. Try it before checking out the solution!

StringBuilder: https://docs.oracle.com/javase/7/docs/api/java/lang/StringBuilder.html
String: https://docs.oracle.com/javase/7/docs/api/java/lang/String.html

My solution for printing out the String:

public static void main(String[] args) {
    String key = "1;2;3;4";
    String value = "Value1;Value2;Value whitespace";

    String[] keys = key.split(";");
    String[] values = value.split(";");

    StringBuilder sb = new StringBuilder("{");
    boolean isKey = true;
    int keyCount = 0;
    int valueCount = 0;

    for(int i = 0; i < key.length(); i++) {
        sb.append("\"");

        if(isKey) {
            sb.append(keys[keyCount]).append("\" : ");
            keyCount++;
        } else {
            sb.append(values[valueCount]).append("\", ");
            valueCount++;
        }
        isKey = !isKey;
    }

    sb.append("}");
    System.out.println(sb.toString());
}
查看更多
你好瞎i
4楼-- · 2019-07-13 13:13

I've come up with a solution to your problem:

Output

{"1" : "Value1", "2" : "Value2", "3" : "Value whitespace", "4" : "null"}       

Code

public class HelloWorld{

     public static void main(String []args){
        String key = "1;2;3;4";
        String value = "Value1;Value2;Value whitespace;";

        String[] keyArr = key.split(";");
        String[] valueArr = value.split(";");

        String finalJSON = "{";
        for(int i=0; i<(keyArr.length > valueArr.length ? keyArr.length : valueArr.length); i++) {

            try {
                finalJSON += "\"" + keyArr[i] + "\"";
            }
            catch(ArrayIndexOutOfBoundsException e) {
                finalJSON += "\"null\"";
            }

            finalJSON += " : ";

            try {
                finalJSON += "\"" + valueArr[i] + "\"";
            }
            catch(ArrayIndexOutOfBoundsException e) {
                finalJSON += "\"null\"";
            }
            if(i!=(keyArr.length > valueArr.length ? keyArr.length : valueArr.length) - 1) 
                finalJSON += ", ";
        }
        finalJSON += "}";

        System.out.println(finalJSON);
     }
}
查看更多
Viruses.
5楼-- · 2019-07-13 13:20

Another - slightly more elegant Java8 and Generic as possible.

/**
 * General pair of items.
 *
 * @param <P> - Type of the first item in the pair.
 * @param <Q> - Type of the second item.
 */
static class Pair<P, Q> {
    final P p;
    final Q q;

    public Pair(P p, Q q) {
        this.p = p;
        this.q = q;
    }

    @Override
    public String toString() {
        return "{" + p + "," + q + "}";
    }
}

/**
 * Gets the `n`th item is present in the array - otherwise returns null.
 *
 * @param a   - The array
 * @param n   - Which one in the array we want.
 * @param <T> - The type of the array entries.
 * @return - The `n`th entry in the array or null if not present.
 */
private static <T> T n(T[] a, int n) {
    return n < a.length ? a[n] : null;
}

/**
 * Pairs up each element in the arrays.
 *
 * @param <P> - The type of the elements in the `P` array.
 * @param <Q> - The type of the elements in the `Q` array.
 * @param ps  - The `P` array.
 * @param qs  - The `Q` array.
 * @return A list of `Pair`s of each element.
 */
static <P, Q> List pairUp(P[] ps, Q[] qs) {
    return IntStream.range(0, Math.max(ps.length, qs.length))
            .mapToObj(i -> new Pair<>(n(ps, i), n(qs, i)))
            .collect(Collectors.toList());
}

/**
 * Splits the two strings on a separator and returns a list of Pairs of the corresponding items.
 *
 * @param a         - The first string.
 * @param b         - The second string.
 * @param separator - The separator.
 * @return - A List of Paired up entries from `a` and `b`.
 */
private static List<Pair<String, String>> fold(String a, String b, String separator) {
    return pairUp(a.split(separator, -1), b.split(separator, -1));
}

public void test() {
    System.out.println(fold("1;2;3;4", "Value1;Value2;Value whitespace", ";"));
}
查看更多
Bombasti
6楼-- · 2019-07-13 13:28

A different point of view: don't do such things "manually".

What I mean is: instead of doing all "low level" operations yourself; you should abstract.

First, transform your key value strings into a Map. Like:

String keys[] = keyString.split(";");
String values[] = valueString.split(";);

... probably some consistency checks that arrays have same length; and  no nulls in keys

Map<String, String> map = new HashMap<>();
for (int i=0; i < keys.length; i++) {
  map.put(keys[i], values[i]);
}

then finally, use some existing JSON library to simply generate a JSON representation based on that map.

In other words: unless you are talking about lists with millions of entries; do not worry about performance. Instead, worry about good abstractions, not re-inventing the wheel and code readability.

But if you really have to worry about performance, or memory aspects, then simply split into arrays, and then use those two arrays as input to some function that uses a StringBuilder to build the required output string.

查看更多
登录 后发表回答