2013-08-14 2 views
1

EDITEDСтрока Манипуляция Сравнение

У меня есть такой строки

  1. "A-B-C-D"
  2. "B-C-A"
  3. "D-A"
  4. "B-A-D"
  5. "D-A-B-C"

Теперь моя проблема, если пользовательский ввод имеет значение "A-C" или "C-A" чисел 1,2,5 будет мой выходом, потому что эти цифры имеют значение «AC», если, например, пользователь имеет вход значение любого из этих трех "A-B-D", "B-A-D", "A-D-B", выход будет 1,4,5. надеюсь, что это очищает вопрос

Примечание: последовательности поиска зависит от пользовательского ввода, и я хочу, чтобы это было более эффективным, потому что у меня есть 10 тысяч данных я не хочу использовать столько цикл, как это возможно.

+1

Если я правильно понял вопрос, вы можете просто разбить каждый символ, используя разделитель '-', а затем прокрутить их и посмотреть, содержит ли каждая строка в наборе строк все символы. –

+0

Я попробую ваше предложение – DevfaR

+0

@DevfaR: Пожалуйста, уточните, хотите ли вы * только * искать двухсимвольные строки, такие как «A-C», или если вы будете искать более длинные строки, такие как «A-D-B». Это источник многих предположений ниже. Если вы ищете только двухсимвольные строки, достаточно просто увидеть, содержит ли входная строка оба символа, независимо от того, имеет ли значение обратное значение. Однако, если вы ищете более длинные строки, тогда требуется другой алгоритм, который обеспечивает порядок поиска. –

ответ

3

Это может меняться в зависимости от вас нужно иметь String в точном шаблоне вы имеете это или нет, но на самом деле просто ...

public class Simple { 

    public static void main(String[] args) { 

     System.out.println("1. " + matches("A-B-C-D")); 
     System.out.println("2. " + matches("B-C-A")); 
     System.out.println("3. " + matches("D-A")); 
     System.out.println("4. " + matches("B-A-D")); 
     System.out.println("5. " + matches("D-A-B-C")); 
    } 

    public static boolean matches(String value) { 

     return value.contains("A") && value.contains("C"); 

    } 
} 

Какие выходы

1. true 
2. true 
3. false 
4. false 
5. true 

Расширенный пример использования переменных сопоставлений

Итак, основная идея - предоставить какой-то список значений, которые должны быть сопоставлены. Этот пример просто использует String (или с переменным числом аргументов String массива), но это не было бы трудно сделать это использовать что-то вроде List

public class Simple { 

    public static void main(String[] args) { 

     String[] match = new String[]{"A", "D", "C"}; 
     System.out.println("1. " + matches("A-B-C-D", match)); 
     System.out.println("2. " + matches("B-C-A", match)); 
     System.out.println("3. " + matches("D-A", match)); 
     System.out.println("4. " + matches("B-A-D", match)); 
     System.out.println("5. " + matches("D-A-B-C", match)); 
    } 

    public static boolean matches(String value, String... matches) { 

     boolean doesMatch = true; 
     for (String match : matches) { 

      if (!value.contains(match)) { 
       doesMatch = false; 
       break; 
      } 

     } 

     return doesMatch; 

    } 
} 

Воспроизводит ...

1. true 
2. false 
3. false 
4. false 
5. true 
+0

Шахта выглядит прохладнее. ;) Хахаха. –

+0

@DummyCode Мне нравится версия reg-exp, возможно, вам нужно будет дать +1 – MadProgrammer

+0

Yay! Хахаха. Уже есть +1. –

2

Используйте массив и пройдите через каждый индекс и посмотрите, содержит ли он «C-A» или «A-C», если он печатает номер.

 String stringArray[] = {"A-B-C-D", "B-C-A", "D-A", "B-A-D", "D-A-B-C"}; 
     for(int i = 0; i < stringArray.length; i++) { 
      String pattern = ".*C-.*A.*"; 
      String pattern2 = ".*A-.*C.*"; 
      if(stringArray[i].matches(pattern) || stringArray[i].matches(pattern2)) 
       System.out.println(i + 1); 
     } 
+0

Это не сработало бы для строки 5. – andy256

+0

@ andy256 Почему? –

+0

@ andy256 Я обновлю регулярное выражение. –

1

Вызовите эту функцию на каждую строку, которую вы хотите проверить. Если он возвращает true, добавьте эту строку в свой результирующий набор.

boolean matches(String s, char[] chars) { 
    for(char c : chars) { 
     if (s.indexOf(c) == -1) { 
      return false; 
     } 
    } 
    return true; 
} 
+0

Мое впечатление, что ОП пытался найти подпоследовательность * в порядке *. –

+1

@JasonC «Я должен получить числа 1,2,5, потому что эти числа имеют C и A в них».Поведение при поиске более 3-х символов не задано в вопросе, однако только с двумя, все упорядочения либо форвард, либо наоборот, если они оба существуют. – Aurand

+0

Да, я согласен с тем, что его вопрос, к сожалению, неоднозначен из-за его примера, имеющего только 2 персонажа. –

1

Edit: Это относится к более старой версии ОП, которая неясна в поиске последовательности в порядке; и поэтому это ищет последовательности по порядку, что сейчас неверно.

Существует много вариантов. Ниже я описываю один подход, который сначала маркерные строки, так и другой, который использует простое регулярное выражение, генерируемое из входной строки.

Подход 1: Синтаксические Струны

Начните с разбором каждого String в массив подстрок, который сделает все эти легче работать. Вы можете разобрать каждую из строк, когда вы изначально читали их вместо каждый раз, когда вам нужно:

String myString = "A-B-C-D"; 
String[] sequence = myString.split("-"); 

Далее, рассмотреть возможность использования List<String> вместо String[], потому что это сделает остальную часть этого немного проще (вы увидите). Таким образом, вместо того выше:

String myString = "A-B-C-D"; 
List<String> sequence = Arrays.asList(myString.split("-")); 

Теперь проблема становится проверка, если два из этих массивов матча:

public static boolean containsSequence (List<String> searchIn, List<String> searchFor) { 
} 

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

public static boolean containsSequence (List<String> searchIn, List<String> searchFor) { 
    // first check forward 
    if (containsSequenceForward(searchIn, searchFor)) 
     return true; 
    // now check in reverse 
    List<String> reversedSearchFor = new ArrayList<String>(searchFor); 
    Collections.reverse(reversedSearchFor); 
    return containsSequenceForward(searchIn, reversedSearchFor); 
} 

public static boolean containsSequenceForward (List<String> searchIn, List<String> searchFor) { 
} 

// usage example: 
public static void example() { 
    List<String> searchIn = Arrays.asList("D-A-B-C".split("-")); 
    List<String> searchFor = Arrays.asList("A-C".split("-")); 
    boolean contained = containsSequence(searchIn, searchFor); 
} 

Теперь вам нужно всего лишь реализовать containsSequenceForward. Я бы хотел, чтобы вы сделали это самостоятельно, но я предоставлю алгоритм в качестве подсказки:

  1. Начало в начале поискаВидео.
  2. Пройдите поиск по одному элементу за раз.
  3. Когда вы найдете текущий элемент searchFor в searchIn, продвигайте поискДля следующего элемента.
  4. Если вы попали в конец поиска, вы нашли последовательность.
  5. Если вы попали в конец поиска, но не искали, то последовательность не соответствует.

Теперь у вас есть возможность проверить, содержит ли одна последовательность другую в любом порядке. Чтобы применить его ко всей вашей коллекции, я рекомендую подготовить все строки в List<String> один раз в начале, тогда вы можете пройти через каждый из них, используя вышеприведенный алгоритм.

Есть много альтернативных вариантов. Например, вы можете использовать indexOf по адресу searchIn, чтобы найти каждый элемент в searchFor и убедиться, что индексы в порядке возрастания.

подход 2: Регулярные выражения

Другим вариантом здесь является использование регулярных выражений, чтобы найти последовательность поиска в исходной строке. Вы можете построить регулярное выражение динамически из последовательности поиска довольно легко:

String searchIn = "D-C-B-A"; 
String searchFor = "C-A"; 

String searchForPattern = searchFor.replace("-", ".*"); // yields "C.*A" 
if (searchIn.matches(".*" + searchForPattern + ".*")) 
    /* then it matches forwards */; 

Тогда матч в обратном направлении, если вперед матч не удается, вы можете просто обратный searchFor и повторить:

String searchForReverse = new StringBuilder(searchFor).reverse().toString(); 
String searchForReversePattern = searchForReverse.replace("-", ".*"); // yields "A.*C" 
if (searchIn.matches(".*" + searchForReversePattern + ".*")) 
    /* then it matches backwards */; 

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

Также оба вышеуказанных подхода предполагают совпадение с регистром - чтобы сделать первый регистр без учета регистра, я бы просто преобразовал строки в нижний регистр перед разбором. Для второго вы можете использовать регулярное выражение без регистров.

Надеюсь, что это поможет. Поработайте на листе бумаги, если вам нужно.

Общая точка входа в исходное положение здесь помогает уменьшить эти проблемы до самых маленьких компонентов.

+0

Обратите внимание, что в соответствии с требованиями OP два символа не должны быть смежными. Достаточно просто 'String # indexOf' или' String # contians'. – Aurand

+0

@Aurand Алгоритм, который я изложил, не требует смежности. Кроме того, мое впечатление от запроса OP (основанного на том, что он явно упоминал поиск в обратном порядке) состоит в том, что подпоследовательность должна появляться в порядке, поэтому 'indexOf' или' contains' в одиночку не будет выполнять эту работу, вам придется проверьте позиции. –

+1

Я уже решил проблему без разделения строки, я использовал код @MadProgrammer, в любом случае, благодаря вашему ответу, может быть, какой-то пользователь найдет это актуальным для своей проблемы :) – DevfaR