Сортировка строки, которая могла содержать или время или расстояние

В последнее время я оказался в вашей ситуации и решил написать свой собственный инструмент - impl_me . Это небольшой Ruby-скрипт, который использует SWIG в качестве бэкэнда парсера. Он записывает в стандартный вывод, так что вы можете комбинировать его с вашим любимым набором инструментов nix find / grep / sed / awk для настройки в соответствии со своими предпочтениями.

Поскольку он написан на Ruby, он должен быть кроссплатформенным. SWIG также кроссплатформенный, поэтому все должно быть в порядке.

На данном этапе это довольно примитивно и не так надежно, как Lazy C ++, с точки зрения анализа странных шаблонов и прочего. Вклад приветствуется:)

5
задан mwilliams 10 June 2009 в 01:35
поделиться

7 ответов

Это ситуация, в которой #sort_by может значительно упростить ваш код:

event_participants = event_participants.sort_by do |s|
    if s =~ /'(\d+):(\d+)\.(\d+)/
        [ $1, $2, $3 ].map { |digits| digits.to_i } 
    else
        []
    end
end.reverse

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

Единственное, что вам не нужно делать, - это преобразовывать цифры в целые числа, что вы, скорее всего, захотите сделать. В противном случае у вас будут проблемы с "100" <"2" # => true . Вот почему я добавил шаг #map .

Кроме того, в вашем регулярном выражении квадратные скобки вокруг \ d не нужны, хотя вы хотите избежать точки, чтобы не соответствует всем символам.

В одном случае код, который я дал, не соответствует ' Код, который вы указали, соответствует ситуации, когда строка не содержит расстояний. Ваш код будет сравнивать их как равные окружающим строкам (что может вызвать проблемы, если алгоритм сортировки предполагает, что равенство является транзитивным. То есть a == b , b == c подразумевает a == c , чего нет в вашем коде: например a = "'10: 00.1" , b = "frog" , c = "'9: 99: 9" ).

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

Ваш код будет сравнивать их как равные окружающим строкам (что может вызвать проблемы, если алгоритм сортировки предполагает, что равенство является транзитивным. То есть a == b , b == c подразумевает a == c , чего нет в вашем коде: например a = "'10: 00.1" , b = "frog" , c = "'9: 99: 9" ).

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

Ваш код будет сравнивать их как равные окружающим строкам (что может вызвать проблемы, если алгоритм сортировки предполагает, что равенство является транзитивным. То есть a == b , b == c подразумевает a == c , чего нет в вашем коде: например a = "'10: 00.1" , b = "frog" , c = "'9: 99: 9" ).

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

что не относится к вашему коду: например a = "'10: 00.1" , b = "frog" , c = "'9: 99: 9 ").

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

что не относится к вашему коду: например a = "'10: 00.1" , b = "frog" , c = "'9: 99: 9 ").

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

4
ответ дан 14 December 2019 в 19:23
поделиться

Вместо реализации подобной сортировки, возможно, вам следует иметь модели TrackTime и FieldDistance. Их не обязательно настаивать - Участник модель может создавать их из time_distance при загрузке.

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

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

1
ответ дан 14 December 2019 в 19:23
поделиться

I не знаю Ruby, но вот какой-то псевдокод, похожий на c, который немного реорганизует его.

/// In c, I would probably shorten this with the ? operator.
int compareIntegers(a, b) {
    int result = 0;
    if (a < b) {
        result = -1;
    } else if (a > b) {
        result = 1;
    }
    return result;
}

int compareValues(a, b) {
    int result = 0;
    if (!/* check for empty*/) {
        int majorA = /* part before first colon */
        int majorB = /* part before first colon */
        int minorA = /* part after first colon */
        int minorB = /* part after first colon */

        /// In c, I would probably shorten this with the ? operator.
        result = compareIntegers(majorA, majorB);
        if (result == 0) {
            result = compareIntegers(minorA, minorB);
        }
    }
    return result;
}
0
ответ дан 14 December 2019 в 19:23
поделиться

Ваша процедура выглядит нормально, но вы можете просто удалить '' ',': 'и'. ' и рассматривать результат как числовую строку. Другими словами, 10 '5 "станет 1005, а 10' 4 'будет 1004. 1005 явно больше, чем 1004.

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

0
ответ дан 14 December 2019 в 19:23
поделиться

Я согласен, что преобразование в целые числа приведет к проще. Также обратите внимание, что для целых чисел

if a > b
  1
elsif a < b
  -1
else 
  0

можно упростить до a <=> b . Чтобы получить обратное, используйте - (a <=> b) .

0
ответ дан 14 December 2019 в 19:23
поделиться

В этом сценарии:

Поскольку вы знаете, что работаете с футами, дюймами и (какой бы ни была ваша третья единица измерения), почему бы просто не создать общую сумму двух сравниваемых значений?

Итак, после этих двух строк:

a_parts = a.time_distance.scan (/'([\d provided):(([\d provided).([\d provided)/) b_parts = b.time_distance.scan (/ '([\ d] ): ([\ d] ). ([\ d] ) /)

Создает общее расстояние для a_parts и b_parts:

totalDistanceA = a_parts [0] [0] .to_i * 12 + a_parts [0] [1] .to_i + b_parts [0] [2] .to_i * (независимо от вашего коэффициента третьей единицы измерения относительно размер дюйма)

totalDistanceB = b_parts [0] [0] .to_i * 12 + b_parts [0] [1] .to_i + b_parts [0] [2] .to_i * (независимо от вашего коэффициента третьей единицы измерения против размера дюйма)

Затем верните сравнение этих двух значений:

totalDistanceA <=> totalDistanceB

Обратите внимание, что вы должны сохранить уже выполняемую проверку, которая проверяет, являются ли a_parts и b_parts пустыми или нет:

a_parts.empty? || b_parts.empty?

Для выполнения сценария сортировки по времени сделайте то же самое, но с другими факторами (например,

0
ответ дан 14 December 2019 в 19:23
поделиться

Почему бы не сделать

a_val = a_parts[0][0].to_i * 10000 + a_parts[0][1].to_i * 100 + a_parts[0][2].to_i
b_val = b_parts[0][0].to_i * 10000 + b_parts[0][1].to_i * 100 + b_parts[0][2].to_i
a_val <=> b_val

Числа не имеют смысла вычитать и т. Д., Но они должны сортироваться нормально.

Вы можете проверить, что [1] и [2] всегда являются двумя цифрами в регулярном выражении.

0
ответ дан 14 December 2019 в 19:23
поделиться
Другие вопросы по тегам:

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