Объект списка отсортированных массивов в Котлине [дубликат]

Ваш код разбит на две полностью отдельные части, серверную сторону и клиентскую сторону .

                    |
               ---------->
              HTTP request
                    |
+--------------+    |    +--------------+
|              |    |    |              |
|    browser   |    |    |  web  server |
| (JavaScript) |    |    |  (PHP etc.)  |
|              |    |    |              |
+--------------+    |    +--------------+
                    |
  client side       |      server side
                    |
               <----------
          HTML, CSS, JavaScript
                    |

Обе стороны общаются через HTTP-запросы и ответы. PHP выполняется на сервере и выводит код HTML и, возможно, JavaScript, который отправляется как ответ клиенту, где интерпретируется HTML, и выполняется JavaScript. Когда PHP завершит вывод ответа, сценарий закончится, и на сервере ничего не произойдет, пока не появится новый HTTP-запрос.

Пример кода выполняется следующим образом:


Шаг 1, PHP выполняет весь код между тегами . В результате получилось следующее:


Вызов file_put_contents не привел ни к чему, он просто написал «+ foo +» в файл. Вызов привел к выводу «42», который теперь находится в том месте, где этот код использовался.

Этот итоговый код HTML / JavaScript теперь отправляется клиенту, где он получает оценку , Вызов alert работает, а переменная foo нигде не используется.

Весь PHP-код выполняется на сервере до того, как клиент даже начнет выполнение какого-либо JavaScript. В ответе JavaScript, с которым может взаимодействовать JavaScript, нет кода PHP.

Чтобы вызвать некоторый код PHP, клиент должен будет отправить новый HTTP-запрос на сервер. Это может произойти с использованием одного из трех возможных способов:

  1. Ссылка, которая заставляет браузер загружать новую страницу.
  2. Подача формы, которая передает данные на сервер и загружает новую страницу.
  3. Запрос AJAX , который является техникой Javascript, чтобы сделать обычный HTTP-запрос на сервер (например, 1. и 2. будет), но без оставляя текущую страницу.

Вот более подробный изложение этого метода

Вы также можете использовать JavaScript, чтобы браузер открыл новую страницу с помощью window.location или отправить форму, подражая возможностям 1 и 2.

66
задан Dave L. 19 September 2008 в 21:56
поделиться

17 ответов

Алфавитный алгоритм

С веб-сайта

«Люди сортируют строки с номерами по-разному, чем программное обеспечение. Большинство алгоритмов сортировки сравнивают значения ASCII,

Изменить: Вот ссылка на реализацию Java Comparator Implementation с этого сайта.

92
ответ дан ScArcher2 23 August 2018 в 21:34
поделиться
  • 1
    Это не полностью решает проблему - вам нужно будет токенизировать строку, которую нужно отсортировать и отсортировать с помощью этого алгоритма на каждой части отдельно. – Nick Johnson 19 September 2008 в 21:06
  • 2
    Примечание. Павел принял ваш ответ, но мой алгоритм более тесно связан с его проблемой (как он объяснил это!), Для таких случаев, как «Allegia 51B Clasteron». Не проблема, он выбирает все, что соответствует его потребностям, и эта реализация Alphanum прекрасна (и многоязычная!), Я просто хотел указать на это. :-П – PhiLho 25 October 2008 в 09:34
  • 3
    обратите внимание, что лицензия GNU-lesser лицензирована – Renaud 11 November 2014 в 23:31
  • 4
    Спасибо. Почему бы вам не нажать на gist.github.com ?! – matthaeus 28 October 2015 в 13:04
  • 5
    Эта реализация связана с конкретными примерами ввода OP, но для общего использования следует помнить, что она не справляется с числами с ведущими нулями. Он считает, что "01234" больше, чем «5678». – Klitos Kyriacou 25 January 2018 в 18:23

Хотя вопрос задал java-решение для любого, кто хочет решение scala:

object Alphanum {

   private[this] val regex = "((?<=[0-9])(?=[^0-9]))|((?<=[^0-9])(?=[0-9]))"

   private[this] val alphaNum: Ordering[String] = Ordering.fromLessThan((ss1: String, ss2: String) => (ss1, ss2) match {
     case (sss1, sss2) if sss1.matches("[0-9]+") && sss2.matches("[0-9]+") => sss1.toLong < sss2.toLong
     case (sss1, sss2) => sss1 < sss2
   })

   def ordering: Ordering[String] = Ordering.fromLessThan((s1: String, s2: String) => {
     import Ordering.Implicits.infixOrderingOps
     implicit val ord: Ordering[List[String]] = Ordering.Implicits.seqDerivedOrdering(alphaNum)

     s1.split(regex).toList < s2.split(regex).toList
   })

}
0
ответ дан Bennie Krijger 23 August 2018 в 21:34
поделиться

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

...
var regex = /(\d+)/g,
    str1Components = str1.split(regex),
    str2Components = str2.split(regex),
...

I.e., 'hello22goodbye 33' => ['hello', 22, 'goodbye', 33]; Таким образом, вы можете перемещаться по элементам массивов в парах между строками1 и строкой2, делать какое-то принуждение типа (например, этот элемент действительно число?) И сравнивать по ходу.

Рабочий пример здесь : http://jsfiddle.net/F46s6/3/

Обратите внимание: в настоящее время я поддерживаю только целочисленные типы, хотя обработка десятичных значений не будет слишком сложной для модификации.

1
ответ дан cdaringe 23 August 2018 в 21:34
поделиться

Я понимаю, что вы в java, но вы можете посмотреть, как работает StrCmpLogicalW. Это то, что Explorer использует для сортировки имен файлов в Windows. Вы можете посмотреть реализацию WINE здесь .

5
ответ дан Eclipse 23 August 2018 в 21:34
поделиться

интересная проблема, и здесь мое предлагаемое решение:

import java.util.Collections;
import java.util.Vector;

public class CompareToken implements Comparable<CompareToken>
{
    int valN;
    String valS;
    String repr;

    public String toString() {
    return repr;
    }

    public CompareToken(String s) {
    int l = 0;
    char data[] = new char[s.length()];
    repr = s;
    valN = 0;
    for (char c : s.toCharArray()) {
        if(Character.isDigit(c))
        valN = valN * 10 + (c - '0');
        else
        data[l++] = c;
    }

    valS = new String(data, 0, l);
    }

    public int compareTo(CompareToken b) {
    int r = valS.compareTo(b.valS);
    if (r != 0)
        return r;

    return valN - b.valN;
    }


    public static void main(String [] args) {
    String [] strings = {
        "aaa",
        "bbb3ccc",
        "bbb12ccc",
        "ccc 11",
        "ddd",
        "eee3dddjpeg2000eee",
        "eee12dddjpeg2000eee"
    };

    Vector<CompareToken> data = new Vector<CompareToken>();
    for(String s : strings)
        data.add(new CompareToken(s));
    Collections.shuffle(data);

    Collections.sort(data);
    for (CompareToken c : data)
        System.out.println ("" + c);
    }

}
1
ответ дан Giuseppe Scrivano 23 August 2018 в 21:34
поделиться

Я придумал довольно простую реализацию на Java с использованием регулярных выражений:

public static Comparator<String> naturalOrdering() {
    final Pattern compile = Pattern.compile("(\\d+)|(\\D+)");
    return (s1, s2) -> {
        final Matcher matcher1 = compile.matcher(s1);
        final Matcher matcher2 = compile.matcher(s2);
        while (true) {
            final boolean found1 = matcher1.find();
            final boolean found2 = matcher2.find();
            if (!found1 || !found2) {
                return Boolean.compare(found1, found2);
            } else if (!matcher1.group().equals(matcher2.group())) {
                if (matcher1.group(1) == null || matcher2.group(1) == null) {
                    return matcher1.group().compareTo(matcher2.group());
                } else {
                    return Integer.valueOf(matcher1.group(1)).compareTo(Integer.valueOf(matcher2.group(1)));
                }
            }
        }
    };
}

Вот как это работает:

final List<String> strings = Arrays.asList("x15", "xa", "y16", "x2a", "y11", "z", "z5", "x2b", "z");
strings.sort(naturalOrdering());
System.out.println(strings);

[x2a, x2b , x15, xa, y11, y16, z, z, z5]

3
ответ дан Helder Pereira 23 August 2018 в 21:34
поделиться

В Linux glibc предоставляет strverscmp (), он также доступен из gnulib для переносимости. Однако действительно «человеческая» сортировка имеет множество других причуд, таких как «The Beatles», которые сортируются как «Beatles, The». Нет простого решения этой общей проблемы.

-1
ответ дан James Antill 23 August 2018 в 21:34
поделиться

Разделите строку на строки букв и цифр, поэтому «foo 12 bar» станет списком («foo», 12, «bar»), а затем используйте список в качестве ключа сортировки. Таким образом, числа будут упорядочены в цифровом порядке, а не в алфавитном порядке.

4
ответ дан John Millikin 23 August 2018 в 21:34
поделиться

Алгоритм Alphanum хорош, но он не соответствует требованиям для проекта, над которым я работаю. Мне нужно иметь возможность правильно сортировать отрицательные числа и десятичные знаки. Вот реализация, которую я придумал. Любая обратная связь будет высоко оценена.

public class StringAsNumberComparator implements Comparator<String> {

    public static final Pattern NUMBER_PATTERN = Pattern.compile("(\\-?\\d+\\.\\d+)|(\\-?\\.\\d+)|(\\-?\\d+)");

    /**
     * Splits strings into parts sorting each instance of a number as a number if there is
     * a matching number in the other String.
     * 
     * For example A1B, A2B, A11B, A11B1, A11B2, A11B11 will be sorted in that order instead
     * of alphabetically which will sort A1B and A11B together.
     */
    public int compare(String str1, String str2) {
        if(str1 == null || str2 == null) {
            return 0;
        }

        List<String> split1 = split(str1);
        List<String> split2 = split(str2);
        int diff = 0;

        for(int i = 0; diff == 0 && i < split1.size() && i < split2.size(); i++) {
            String token1 = split1.get(i);
            String token2 = split2.get(i);

            if((NUMBER_PATTERN.matcher(token1).matches() && NUMBER_PATTERN.matcher(token2).matches()) {
                diff = (int) Math.signum(Double.parseDouble(token1) - Double.parseDouble(token2));
            } else {
                diff = token1.compareToIgnoreCase(token2);
            }
        }
        if(diff != 0) {
            return diff;
        } else {
            return split1.size() - split2.size();
        }
    }

    /**
     * Splits a string into strings and number tokens.
     */
    private List<String> split(String s) {
        List<String> list = new ArrayList<String>();
        try (Scanner scanner = new Scanner(s)) {
            int index = 0;
            String num = null;
            while ((num = scanner.findInLine(NUMBER_PATTERN)) != null) {
                int indexOfNumber = s.indexOf(num, index);
                if (indexOfNumber > index) {
                    list.add(s.substring(index, indexOfNumber));
                }
                list.add(num);
                index = indexOfNumber + num.length();
            }
            if (index < s.length()) {
                list.add(s.substring(index));
            }
        }
        return list;
    }
}

PS. Я хотел использовать метод java.lang.String.split () и использовать «lookahead / lookbehind» для сохранения токенов, но я не мог заставить его работать с регулярным выражением, которое я использовал.

2
ответ дан JustinKSU 23 August 2018 в 21:34
поделиться
  • 1
    Вы можете захотеть кэшировать ваши вызовы Pattern.compile(), учитывая, что они вызваны с O(N log N) сложностью! – Lukas Eder 23 February 2018 в 12:42
  • 2
    Хорошее предложение. Код обновляется. Сканер также теперь закрыт, используя «попробуйте с ресурсами». – JustinKSU 23 February 2018 в 17:20

Реализация, которую я предлагаю здесь, проста и эффективна. Он не выделяет никакой дополнительной памяти прямо или косвенно с помощью регулярных выражений или методов, таких как substring (), split (), toCharArray () и т. Д.

. Эта реализация сначала пересекает обе строки для поиска первые символы, которые отличаются, на максимальной скорости, без какой-либо специальной обработки во время этого. Конкретное сравнение чисел запускается только тогда, когда эти символы являются двумя цифрами. Побочным эффектом этой реализации является то, что цифра считается большей, чем другие буквы, в отличие от лексикографического порядка по умолчанию.

public static final int compareNatural (String s1, String s2)
{
   // Skip all identical characters
   int len1 = s1.length();
   int len2 = s2.length();
   int i;
   char c1, c2;
   for (i = 0, c1 = 0, c2 = 0; (i < len1) && (i < len2) && (c1 = s1.charAt(i)) == (c2 = s2.charAt(i)); i++);

   // Check end of string
   if (c1 == c2)
      return(len1 - len2);

   // Check digit in first string
   if (Character.isDigit(c1))
   {
      // Check digit only in first string 
      if (!Character.isDigit(c2))
         return(1);

      // Scan all integer digits
      int x1, x2;
      for (x1 = i + 1; (x1 < len1) && Character.isDigit(s1.charAt(x1)); x1++);
      for (x2 = i + 1; (x2 < len2) && Character.isDigit(s2.charAt(x2)); x2++);

      // Longer integer wins, first digit otherwise
      return(x2 == x1 ? c1 - c2 : x1 - x2);
   }

   // Check digit only in second string
   if (Character.isDigit(c2))
      return(-1);

   // No digits
   return(c1 - c2);
}
5
ответ дан Olivier Oudot 23 August 2018 в 21:34
поделиться

Короткий ответ: исходя из контекста, я не могу сказать, является ли это всего лишь очень быстро и грязным кодом для личного использования или ключевой частью последнего внутреннего программного обеспечения Goldman Sachs, поэтому я открою говоря: eww. Это довольно забавный алгоритм сортировки; попробуйте использовать что-то немного менее «извилистым», если сможете.

Длинный ответ:

Два вопроса, которые сразу приходят вам в голову в вашем случае, - это производительность и правильность. Неформально убедитесь, что это быстро, и убедитесь, что ваш алгоритм является общим порядком .

(Конечно, если вы не сортируете более 100 предметов, вы, вероятно, можете пренебрегайте этим пунктом.) Эффективность имеет значение, так как скорость компаратора будет наибольшим фактором в скорости вашего сортировки (если алгоритм сортировки «идеален» для типичного списка). В вашем случае скорость компаратора будет зависеть в основном от размера строки. Строки кажутся довольно короткими, поэтому они, вероятно, не будут доминировать так же, как размер вашего списка.

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

Другая проблема - правильность. В частности, если алгоритм, который вы описали, когда-либо разрешит A> B> ...> A, тогда ваш вид будет недетерминированным. В вашем случае я боюсь, что это возможно, хотя я не могу это доказать. Рассмотрим некоторые примеры синтаксического анализа, такие как:

  aa 0 aa
  aa 23aa
  aa 2a3aa
  aa 113aa
  aa 113 aa
  a 1-2 a
  a 13 a
  a 12 a
  a 2-3 a
  a 21 a
  a 2.3 a
0
ответ дан Paul Brinkley 23 August 2018 в 21:34
поделиться

Интересная небольшая проблема, мне понравилось ее решать.

Вот мой подход к проблеме:

String[] strs =
{
  "eee 5 ddd jpeg2001 eee",
  "eee 123 ddd jpeg2000 eee",
  "ddd",
  "aaa 5 yy 6",
  "ccc 555",
  "bbb 3 ccc",
  "bbb 9 a",
  "",
  "eee 4 ddd jpeg2001 eee",
  "ccc 11",
  "bbb 12 ccc",
  "aaa 5 yy 22",
  "aaa",
  "eee 3 ddd jpeg2000 eee",
  "ccc 5",
};

Pattern splitter = Pattern.compile("(\\d+|\\D+)");

public class InternalNumberComparator implements Comparator
{
  public int compare(Object o1, Object o2)
  {
    // I deliberately use the Java 1.4 syntax, 
    // all this can be improved with 1.5's generics
    String s1 = (String)o1, s2 = (String)o2;
    // We split each string as runs of number/non-number strings
    ArrayList sa1 = split(s1);
    ArrayList sa2 = split(s2);
    // Nothing or different structure
    if (sa1.size() == 0 || sa1.size() != sa2.size())
    {
      // Just compare the original strings
      return s1.compareTo(s2);
    }
    int i = 0;
    String si1 = "";
    String si2 = "";
    // Compare beginning of string
    for (; i < sa1.size(); i++)
    {
      si1 = (String)sa1.get(i);
      si2 = (String)sa2.get(i);
      if (!si1.equals(si2))
        break;  // Until we find a difference
    }
    // No difference found?
    if (i == sa1.size())
      return 0; // Same strings!

    // Try to convert the different run of characters to number
    int val1, val2;
    try
    {
      val1 = Integer.parseInt(si1);
      val2 = Integer.parseInt(si2);
    }
    catch (NumberFormatException e)
    {
      return s1.compareTo(s2);  // Strings differ on a non-number
    }

    // Compare remainder of string
    for (i++; i < sa1.size(); i++)
    {
      si1 = (String)sa1.get(i);
      si2 = (String)sa2.get(i);
      if (!si1.equals(si2))
      {
        return s1.compareTo(s2);  // Strings differ
      }
    }

    // Here, the strings differ only on a number
    return val1 < val2 ? -1 : 1;
  }

  ArrayList split(String s)
  {
    ArrayList r = new ArrayList();
    Matcher matcher = splitter.matcher(s);
    while (matcher.find())
    {
      String m = matcher.group(1);
      r.add(m);
    }
    return r;
  }
}

Arrays.sort(strs, new InternalNumberComparator());

Этот алгоритм требует гораздо большего тестирования, но, похоже, он ведет себя довольно красиво.

[EDIT] Я добавил еще несколько комментариев, чтобы быть более четкими. Я вижу, что ответов гораздо больше, чем когда я начал кодировать это ... Но я надеюсь, что я дал хорошую стартовую базу и / или некоторые идеи.

12
ответ дан PhiLho 23 August 2018 в 21:34
поделиться
  • 1
    хороший! Еще один нуль и экземпляр проверки строки тоже был бы хорош – HRgiger 10 May 2016 в 09:34
  • 2
    @HRgiger У вас есть точка с нулевой проверкой, я предположил, что массив был «здравым». Но сегодня я бы просто отказался от синтаксиса до Java 1.5 и использовал generics, а не instanceof. – PhiLho 11 May 2016 в 14:50

Ян Гриффитс из Microsoft имеет реализацию C #, которую он называет Natural Sorting .

UPDATE: Кажется, есть пример Java на eekboom , который делает это, см. «CompareNatural» и используйте что как ваш компартер сортирует.

8
ответ дан Ray Hayes 23 August 2018 в 21:34
поделиться

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

0
ответ дан sblundy 23 August 2018 в 21:34
поделиться

В вашем примере числа, которые вы хотите сравнить, имеют пробелы вокруг них, а другие числа - нет, поэтому почему регулярное выражение не работает?

bbb 12 ccc

vs.

eee 12 ddd jpeg2000 eee

-1
ответ дан scubabbl 23 August 2018 в 21:34
поделиться

Мои 2 цента. Я хорошо работаю для меня. Я в основном использую его для имен файлов.

    private final boolean isDigit(char ch)
        {
            return ch >= 48 && ch <= 57;
        }


        private int compareNumericalString(String s1,String s2){

            int s1Counter=0;
            int s2Counter=0;
            while(true){
                if(s1Counter>=s1.length()){
                    break;
                }
                if(s2Counter>=s2.length()){
                    break;
                }
                char currentChar1=s1.charAt(s1Counter++);
                char currentChar2=s2.charAt(s2Counter++);
                if(isDigit(currentChar1) &&isDigit(currentChar2)){
                    String digitString1=""+currentChar1;
                    String digitString2=""+currentChar2;
                    while(true){
                        if(s1Counter>=s1.length()){
                            break;
                        }
                        if(s2Counter>=s2.length()){
                            break;
                        }

                        if(isDigit(s1.charAt(s1Counter))){
                            digitString1+=s1.charAt(s1Counter);
                            s1Counter++;
                        }

                        if(isDigit(s2.charAt(s2Counter))){
                            digitString2+=s2.charAt(s2Counter);
                            s2Counter++;
                        }

                        if((!isDigit(s1.charAt(s1Counter))) && (!isDigit(s2.charAt(s2Counter)))){
                            currentChar1=s1.charAt(s1Counter);
                            currentChar2=s2.charAt(s2Counter);
                            break;
                        }
                    }
                    if(!digitString1.equals(digitString2)){
                        return Integer.parseInt(digitString1)-Integer.parseInt(digitString2);
                    }
                }

                if(currentChar1!=currentChar2){
                    return currentChar1-currentChar2;
                }

            }
            return s1.compareTo(s2);
        }
1
ответ дан specialscope 23 August 2018 в 21:34
поделиться

Если вы пишете класс компаратора, вы должны реализовать свой собственный метод сравнения, который будет сравнивать два символа строки по символу. Этот метод сравнения должен проверять, имеете ли вы дело с алфавитными символами, числовыми символами или смешанными типами (включая пробелы). Вам нужно будет определить, как вы хотите, чтобы смешанный тип действовал, независимо от того, поступают ли цифры до буквенных символов или после, и где пробелы вставляются и т. Д.

-1
ответ дан user 23 August 2018 в 21:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: