У меня есть две строки, которые выглядят так:

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

И я хочу сравнить их и быть равными, несмотря на разницу в порядке ...

Какой самый быстрый и простой способ сделать это?

Должен ли я разделить каждый из них на массивы и сравнить два массива? Или нет? Я думаю, мне нужно удалить символы "[", "]", "" ", чтобы сделать это более понятным, как я сделал. И я также заменил", "на" ", но я не знаю, помогает ли это ...

Заранее спасибо :)

Редактировать: Мои строки не всегда будут двойными или плавающими. Они также могут быть реальными словами или набором символов.

2
T. Kofidis 4 Сен 2017 в 15:27

5 ответов

Лучший ответ

Это можно сделать с помощью нижеприведенного метода создания набора строк, который реализован с использованием TreeSet , чтобы сортировка могла быть встроенной. это просто простое преобразование как в строку набора, так и сравнение с использованием метода equals. попробуйте код ниже:

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");
       }

Здесь, в приведенном выше коде, я использовал jsonArray , чтобы удалить символ "\" .

< Сильный > Примечание :

Но это не сработает, если дублированный элемент в одной строке и другой строке отличается по количеству, потому что set не сохраняет дубликаты.

Попробуйте использовать список , в котором хранятся дубликаты элементов, и решите свою проблему.

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");
            }
1
Raju Sharma 4 Сен 2017 в 14:37

Поскольку у вас смешанный тип результата, вам нужно сначала обработать его как смешанный ввод

Вот как я бы его заменил, особенно для более длинных струн.

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
}

Теперь у нас есть поток строк, которые нужно проанализировать либо в примитиве, либо в строке (так как я предполагаю, что у нас нет какой-то странной формы сериализации объектов):

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
    }
}

Используя это, мы можем затем преобразовать наш смешанный поток в смешанную коллекцию:

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
}

Наконец, примером некоторых проверок работоспособности может быть обеспечение того, что такие вещи, как соответствующие фигурные скобки, находятся во входной строке и т. Д. Несмотря на то, что другие говорили, я узнал установленный синтаксис как {a, b, ...c} и синтаксис серии / списка как {{X1} }, оба из которых имеют различные сравнения здесь.

1
Rogue 4 Сен 2017 в 14:13

Нравится:

    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);

Или вы можете использовать полностью функциональный подход (который может быть несколько менее эффективным):

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

Преимущество использования массивов перед использованием наборов (как предлагалось другими) состоит в том, что массивы обычно используют меньше памяти и могут содержать дубликаты. Если ваш проблемный домен может включать повторяющиеся элементы в каждой строке, то наборы использовать нельзя.

0
DodgyCodeException 4 Сен 2017 в 13:01

Это довольно простое решение для вас, используя HashSet.

Преимущества набора: -

  • Он не может содержать дубликат.
  • Вставка / удаление элемента - это O (1).
  • Довольно намного быстрее, чем Array. Здесь сохранение элемента Order также не важно, так что все в порядке.

    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") );
    

Выход:

set1: [0.7710, 0.2487, 0.7419]
set2: [0.7710, 0.2487, 0.7419]
str1 and str2 Equal
0
nagendra547 4 Сен 2017 в 13:25

Google GSON может довольно аккуратно справиться с этой задачей, читая значения как 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));

Выход:

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
0
yegodm 4 Сен 2017 в 14:21