Вернуть Int ищу не Brute Force алгоритм
Задача простая, вернуть Int, на вход получаем String (нескольких типов). Нужно вернуть Int максимально приблеженный.
//12M -> 12000000
//26.8M -> 26800000
//47K -> 47000
//27.8K -> 27800
//1,171 -> 1171
//232 -> 232
Интересует не столько готовый код, сколько обсудить наиболее лаконичную и эффективную идею. Я вижу так:
- Прверяем строку на содержание букв "K", "M", ","
- Проверяем есть ли "." Если нет, берем все что до позиции К или М каким нибудь substring() Умножаем на 1_000 или на 1_000_000 в зависимости от ветки выполнения.
- Если есть . то считаем положение точки ... Сабстринг .... В общем у меня строк на 40 решение выйдет. Чуть позже добавлю его.
Может есть у кого-то не брут форс методы, а то алгоритмы не моя сильная сторона.
П.С. Задача не с Codewars/LeetCode а с реального проекта
Ответы (3 шт):
Предлагаю такую реализацию. Создаем enum со всеми префиксами и их значениями:
enum class Metric(val prefix: String, val multiplier: Int) {
MEGA("M", 1_000_000),
KILO("K", 1_000),
NONE("", 1),
}
Далее, пишем такую вспомогательную функцию по парсингу строки в число:
fun parse(string: String): Long {
for (metric in Metric.values()) {
if (string.endsWith(metric.prefix)) {
val number = NumberFormat.getInstance(Locale.ROOT).parse(string)
return (number.toDouble() * metric.multiplier).toLong()
}
}
throw UnsupportedOperationException()
}
Результат:
parse("12M") # 12000000
parse("26.8M") # 26800000
parse("47K") # 47000
parse("27.8K") # 27800
parse("1,171") # 1171
parse("232") # 232
class Program {
public static double parse(String str) {
return Double.parseDouble(str.replace(",", "").replace("K", "e3").replace("M", "e6"));
}
public static void main(String[] args) {
for (String x : new String[] { "12M", "26.8M", "47K", "27.8K", "1,171", "232" }) {
System.out.printf("%s => %f\n", x, parse(x));
}
}
}
12M => 12000000.000000
26.8M => 26800000.000000
47K => 47000.000000
27.8K => 27800.000000
1,171 => 1171.000000
232 => 232.000000
Если нужно целое, то можно после Double.parseDouble привести к int или long (впрочем, вместо 63 точных битов можно рассчитывать только на 53).
Для парсинга числа можно воспользоваться классом DecimalFormat, для сопоставления буквенного суффикса - мапой значений. Число и суффикс можно определить при помощи регулярного выражения (?i)(\d[\d.,]*)([kmg]?):
(?i)- сравнение без учета регистра(\d[\d.,]*)- группа 1 - число([kmg]?)- группа 2 - опциональный суффикс
Map<String, Long> suffixes = Map.of(
"K", 1_000L,
"M", 1_000_000L,
"G", 1_000_000_000L
);
DecimalFormat df = new DecimalFormat("#,###.#", new DecimalFormatSymbols(Locale.US));
Pattern p = Pattern.compile("(?i)(\\d[\\d.,]*)([kmg]?)");
for (String s : new String[]{"0.01M", "1k", "2,345", "3.456g", "7,890,123.456K", "7654k"}) {
Matcher m = p.matcher(s);
if (m.find()) {
long v = (long)(df.parse(m.group(1)).doubleValue() * suffixes.getOrDefault(m.group(2).toUpperCase(), 1L));
System.out.println(s + " -> " + v);
} else {
System.out.println("Non-matched: " + s);
}
}
0.01M -> 10000
1k -> 1000
2,345 -> 2345
3.456g -> 3456000000
7,890,123.456K -> 7890123456
7654k -> 7654000