T. Kofidis
T. Kofidis

Reputation: 57

Java: Compare Strings with keywords in different order

I have two Strings that look like this:

String str1 = "[0.7419,0.7710,0.2487]";
String str2 = "[\"0.7710\",\"0.7419\",\"0.2487\"]";

and I want to compare them and be equal despite the order difference...

Which is the fastest and simplest way to do that?

Should I split each one into Arrays and compare the two Arrays? Or not? I guess I have to remove the "[","]",""" characters to make it clearer so I did. And I also replaced the "," with " " but I don't know if this helps...

Thanks in advance :)

Edit: My Strings will not always be a set of doubles or floats. They may also be actual words or a set of characters.

Upvotes: 3

Views: 2562

Answers (5)

Raju Sharma
Raju Sharma

Reputation: 2516

This could be done by below a method of making a set of string which is implemented using TreeSet so sorting can be handles in built. it just a simple convert both in string of set and compare using equals method. try below code:

String str1 = "[0.7419,0.7710,0.2487]";
        String str2 = "[\"0.7710\",\"0.7419\",\"0.2487\"]";
        String jsonArray = new JSONArray(str2).toString();
        Set<String> set1 = new TreeSet<String>(Arrays.asList(str1.replace("[", "").replace("]", "").split(",")));
        Set<String> set2 = new TreeSet<String>(Arrays.asList(jsonArray.replace("[", "").replace("]", "").replace("\"", "").split(",")));
        if(set1.equals(set2)){
             System.out.println(" str1 and str2 are equal");
       }

Here in above code i took help of jsonArray, to remove "\" character.

Note:

But this will not work if duplicate element in one string and other string are different in number because set does not keep duplicates.

Try using list that keeps duplicate element and solve your problem.

String str1 = "[0.7419,0.7710,0.2487]";
            String str2 = "[\"0.7710\",\"0.7419\",\"0.2487\"]";
            String jsonArray = new JSONArray(str2).toString();
            List<String> list1=new ArrayList<String>(Arrays.asList(str1.replace("[", "").replace("]", "").split(",")));
            List<String> list2=new ArrayList<String>(Arrays.asList(jsonArray.replace("[", "").replace("]", "").replace("\"", "").split(",")));
            Collections.sort(list1);
            Collections.sort(list2);
            if(list1.equals(list2)){
                  System.out.println("str1 and str2 are equal");
            }

Upvotes: 1

yegodm
yegodm

Reputation: 1044

Google GSON can handle this task quite neatly by reading values as a Set<String>:

    final String str1 = "[0.7419,0.7710,0.2487]";
    final String str2 = "[\"0.7710\",\"0.7419\",\"0.2487\"]";
    final String str3 = "[\"0.3310\",\"0.7419\",\"0.2487\"]";
    final Gson gson = new Gson();
    final Type setOfStrings = new TypeToken<Set<String>>() {}.getType();
    final Set<String> set1 = gson.fromJson(str1, setOfStrings);
    final Set<String> set2 = gson.fromJson(str2, setOfStrings);
    final Set<String> set3 = gson.fromJson(str3, setOfStrings);

    System.out.println("Set #1:" + set1);
    System.out.println("Set #2:" + set2);
    System.out.println("Set #3:" + set3);
    System.out.println("Set #1 is equivalent to Set #2: " + set1.equals(set2));
    System.out.println("Set #1 is equivalent to Set #3: " + set1.equals(set3));

The output is:

Set #1:[0.7419, 0.7710, 0.2487]
Set #2:[0.7710, 0.7419, 0.2487]
Set #3:[0.3310, 0.7419, 0.2487]
Set #1 is equivalent to Set #2: true
Set #1 is equivalent to Set #3: false

Upvotes: 0

Rogue
Rogue

Reputation: 11483

Because you have a mixed result type, you need to first handle it as a mixed input

Here's how I would replace it, particularly for longer strings.

private Stream<String> parseStream(String in) {
    //we'll skip regex for now and can simply hard-fail bad input later
    //you can also do some sanity checks outside this method
    return Arrays.stream(in.substring(1, in.length() - 1).split(",")) //remove braces
        .map(s -> !s.startsWith("\"") ? s : s.substring(1, s.length() - 1)); //remove quotes
}

Following up, we now have a stream of strings, which need to be parsed into either a primitive or a string (since I'm assuming we don't have some weird form of object serialization):

private Object parse(String in) {
    //attempt to parse as number first. Any number can be parsed as a double/long
    try {
        return in.contains(".") ? Double.parseDouble(in) : Long.parseLong(in);
    } catch (NumberFormatException ex) {
        //it's not a number, so it's either a boolean or unparseable
        Boolean b = Boolean.parseBoolean(in); //if not a boolean, #parseBoolean is false
        b = in.toLowerCase().equals("false") && !b ? b : null; //so we map non-false to null
        return b != null ? b : in; //return either the non-null boolean or the string
    }
}

Using this, we can then convert our mixed stream to a mixed collection:

Set<Object> objs = this.parseStream(str1).map(this::parse).collect(Collectors.toSet());
Set<Object> comp = this.parseStream(str2).map(this::parse).collect(Collectors.toSet());
//we're using sets, keep in mind the nature of different collections and how they compare their elements here
if (objs.equals(comp)) {
    //we have a matching set
}

Lastly, an example of some sanity checks would be ensuring things like the appropriate braces are on the input string, etc. Despite what others said I learned the set syntax as {a, b, ...c}, and series/list syntax as [a, b, ...c], both of which have different comparisons here.

Upvotes: 2

nagendra547
nagendra547

Reputation: 6302

This is pretty simple solution for you using HashSet.

Benefits of Set:-

  • It cannot contains duplicate.
  • Insertion/deletion of element is O(1).
  • Pretty much faster than Array. Here keeping the element Order is also not important so it's okay.

    String str1 = "[0.7419,0.7710,0.2487]";
    String str2 = "[\"0.7710\",\"0.7419\",\"0.2487\"]";
    
    Set<String> set1 = new HashSet<>();
    Set<String> set2 = new HashSet<>();
    
    String[] split1 = str1.replace("[", "").replace("]", "").split(",");
    String[] split2 = str2.replace("[", "").replace("]", "").replace("\"", "").split(",");
    set1.addAll(Arrays.asList(split1));
    set2.addAll(Arrays.asList(split2));
    
    System.out.println("set1: "+set1);
    System.out.println("set2: "+set2);
    
    boolean isEqual = false;
    if(set1.size() == set2.size()){
        set1.removeAll(set2);
        if(set1.size() ==0){
            isEqual = true;
        }
    }
    
    System.out.println("str1 and str2 "+( isEqual ? "Equal" : "Not Equal") );
    

output:

set1: [0.7710, 0.2487, 0.7419]
set2: [0.7710, 0.2487, 0.7419]
str1 and str2 Equal

Upvotes: 0

DodgyCodeException
DodgyCodeException

Reputation: 6123

Like this:

    String[] a1 = str1.replaceAll("^\\[|\\]$", "").split(",", -1);
    String[] a2 = str2.replaceAll("^\\[|\\]$", "").split(",", -1);
    for (int i = 0; i < a2.length; i++)
        a2[i] = a2[i].replaceAll("^\\\"|\\\"$", "");
    Arrays.sort(a1);
    Arrays.sort(a2);
    boolean stringsAreEqual = Arrays.equals(a1, a2);

Or you can use a fully functional approach (which may be slightly less efficient):

    boolean stringsAreEqual = Arrays.equals(
            Arrays.stream(str1.replaceAll("^\\[|\\]$", "").split(",", -1))
                    .sorted()
                    .toArray(),
            Arrays.stream(str2.replaceAll("^\\[|\\]$", "").split(",", -1))
                    .map(s -> s.replaceAll("^\\\"|\\\"$", ""))
                    .sorted()
                    .toArray()
    );

The advantage of using arrays over using sets (as proposed by others) is that arrays typically use less memory and they can hold duplicates. If your problem domain can include duplicate elements in each string, then sets can't be used.

Upvotes: 0

Related Questions