Изучающий Javascript здесь.
Проблема: У меня есть список шестнадцатеричных диапазонов, и мне нужно вернуть значение, если значение запроса находится в пределах диапазона. Данные выглядят так:
[
{...},
{"start": 0x3C0000, "end": 0x3FFFFF, "country": "Germany"},
{"start": 0x044000, "end": 0x044FFF, "country": "Ghana"},
{...}
]
У меня есть шестнадцатеричное значение, и я хотел бы получить страну, если шестнадцатеричное значение находится между началом и концом.
Вопрос 1: Каким будет наиболее эффективный способ вернуть страну, если запрос находится между началом и концом?
Вопрос 2: Будет ли более разумный способ форматирования данных, который позволит выполнять более быстрый/эффективный запрос?
Цель моих вопросов — изучить альтернативы перебору массива с помощью цикла.
Ваш набор данных должен быть довольно большим, прежде чем производительность / «эффективность» различных подходов действительно начнет иметь значение. Учитывая, что в мире 195 стран, я сомневаюсь, что дело обстоит именно так. «Цель моих вопросов — изучить альтернативы перебору массива с помощью цикла». - затем ознакомьтесь с методами массива, такими как developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
array.find(x => и проверьте, находится ли запрос между x.start и x.end
Простым способом оптимизации может быть сортировка массива по свойству start
. Затем вы можете выполнить бинарный поиск в списке. Или вы можете создать дерево поиска
@derpirscher: Вы правы, объяснение как-то исчезло, когда я написал вопрос. Вероятно, случайно нажал Shift при редактировании или что-то в этом роде. Добавил объяснение сейчас.
Обычный цикл for
, вероятно, будет наиболее эффективным методом.
При этом есть элегантное решение с filter
и map
.
let res = array.filter(o => x.start <= query && query <= x.end).map(o => o.country);
Конечно, если вам нужен только один результат, используйте вместо него Array#find
.
let res = array.find(o => x.start <= query && query <= x.end)?.country;
почему цикл for быстрее фильтра. это потому что карта тогда не нужна?
@cmgchess В общем, с обычным циклом for меньше накладных расходов. Вы можете посмотреть на них: stackoverflow.com/questions/53072292/… , stackoverflow.com/questions/31459395/…
@cmgchess Потому что с filter
или find
всегда придется вызывать дополнительную функцию (то есть обратный вызов) для каждого элемента, что создает некоторые накладные расходы.
Спасибо @Unmitigated! За решение и особенно за ссылки! Для новичка было довольно интересно читать!
Мы не можем сделать за O(n), если диапазон не отсортирован. Но для последующих операций мы можем сделать за O(log(n)), учитывая, что конечные точки диапазона можно расположить на числовой прямой без какой-либо внутренней фрагментации. (т.е. [2,3], [5,6] содержит внутреннюю фрагментацию, а [2,3],[3,4] — нет).
Итак, давайте возьмем рассматриваемые значения диапазона в виде
{{x1,y1,v1},{x2,y2,v2}...{xn,yn,vn}}
и предположим, что он отсортирован. Если это невозможно, вы можете предположить, что можете, и считать, что оно имеет какое-то нулевое значение.
Таким образом, мы получаем диапазон в числовой строке как
[x1,y1,x2,y2,x3,y3....xn,yn]
для нашего примера, где y1<=x2,y2<=x3
(другие сравнения тривиальны, так как это конечные точки диапазона).
Теперь создайте массив, содержащий значения конечных точек диапазона. Вы можете использовать либо 1-ю конечную точку, либо последнюю конечную точку диапазона. Для нашего примера возьмем первую конечную точку. 0-й индекс соответствует v1, 1-й — null (в диапазоне [y1,x2]
нет значения, как упоминалось ранее). Здесь мы используем стандартный модуль bisect Python для эффективной индексации. Подайте диапазон точек останова (для нашего примера это x1,y1,x2,y2 .. xn,yn) с вашим значением запроса (возьмем xi).
(Вы можете применить ту же логику в js)
import bisect as bst
breakpoint = [x1,y1,x2,y2,x3,y3...xn,yn]
query = xi
rangeValueMap = [v1,null,v2,null...]
value = bst.bisect(breakpoint,query)
if value==null:
print("No range covers the value {0}".format(query))
else:
print("Value is %d"%(value))
Используйте индекс, возвращенный из bisect, чтобы получить значение из уже созданного массива. Если это null , то диапазон не существует, иначе он существует и использует значение.
Какой "запрос"? Пожалуйста, добавьте несколько примеров входных данных и ожидаемых результатов ... И в зависимости от того, сколько элементов в вашем списке, оптимизация может даже не стоить усилий.