В последнее время я оказался в вашей ситуации и решил написать свой собственный инструмент - impl_me . Это небольшой Ruby-скрипт, который использует SWIG в качестве бэкэнда парсера. Он записывает в стандартный вывод, так что вы можете комбинировать его с вашим любимым набором инструментов nix find
/ grep
/ sed
/ awk
для настройки в соответствии со своими предпочтениями.
Поскольку он написан на Ruby, он должен быть кроссплатформенным. SWIG также кроссплатформенный, поэтому все должно быть в порядке.
На данном этапе это довольно примитивно и не так надежно, как Lazy C ++, с точки зрения анализа странных шаблонов и прочего. Вклад приветствуется:)
Это ситуация, в которой #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
также имеет то преимущество, что анализирует значения сравнения только один раз, тогда как вашему алгоритму придется анализировать каждую строку для каждого сравнения.
Вместо реализации подобной сортировки, возможно, вам следует иметь модели TrackTime и FieldDistance. Их не обязательно настаивать - Участник модель может создавать их из time_distance при загрузке.
Вы, вероятно, захотите иметь возможность получать разницу между двумя значениями, проверять значения, а также сортировать значения в будущем. Модель позволит легко добавить эти функции. Также это упростило бы модульное тестирование.
Я бы также разделил время и расстояние на два отдельных поля. По моему опыту, наличие столбцов двойного назначения в базе данных вызывает только проблемы.
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;
}
Ваша процедура выглядит нормально, но вы можете просто удалить '' ',': 'и'. ' и рассматривать результат как числовую строку. Другими словами, 10 '5 "станет 1005, а 10' 4 'будет 1004. 1005 явно больше, чем 1004.
Поскольку элементы более высокого порядка находятся слева, сортировка будет выполняться естественным образом. Это также работает со временем по тем же причинам.
Я согласен, что преобразование в целые числа приведет к проще. Также обратите внимание, что для целых чисел
if a > b
1
elsif a < b
-1
else
0
можно упростить до a <=> b
. Чтобы получить обратное, используйте - (a <=> b)
.
В этом сценарии:
Поскольку вы знаете, что работаете с футами, дюймами и (какой бы ни была ваша третья единица измерения), почему бы просто не создать общую сумму двух сравниваемых значений?
Итак, после этих двух строк:
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?
Для выполнения сценария сортировки по времени сделайте то же самое, но с другими факторами (например,
Почему бы не сделать
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] всегда являются двумя цифрами в регулярном выражении.