Вот типичный пример того, что мне нужно сделать
$testArr = array(2.05080E6,29400,420);
$stockArrays = array(
array(2.05080E6,29400,0),
array(2.05080E6,9800,420),
array(1.715E6,24500,280),
array(2.05080E6,29400,140),
array(2.05080E6,4900,7));
Мне нужно определить stockArray, который наименее отличается. Несколько уточнений
Складские массивы всегда будут иметь одинаковое количество элементов. Тестовый массив будет иметь одинаковые или меньшие элементы. Однако, когда будет добавлено меньше testArr, чтобы потенциально совпадающие элементы всегда находились в том же месте, что и stockArray. например
$ TestArray (29400,140)
будет преобразован в
$testArray(0,29400,140);
до того, как подвергнуться разностному тестированию.
В моем примере результат будет
$result = array(0=>array(0,0,1),3=>array(0,0,1));
что указывает на то, что наименее разные массивы акций имеют индексы 0 & 3 с отличиями в положении 2.
В PHP я бы справился со всем этим array_diff как моя отправная точка. Для Node / JavaScript я бы, вероятно, испытал бы соблазн php.js array_diff Порт, хотя я был бы склонен исследовать немного, учитывая, что в худшем сценарии броска это дело O (n2).
Я новичок, когда дело доходит до Голанга, поэтому я не уверен, как бы я реализовал эту проблему там. Я заметил, что у Node есть модуль array_diff npm.
У меня была одна необычная идея — преобразовать массив в дополненную строку (меньшие элементы массива дополнены 0) и эффективно выполнить XOR для порядкового значения каждого символа, но отклонил это как, вероятно, довольно сумасшедшую вещь.
Я обеспокоен скоростью, но не любой ценой. В идеальном мире одно и то же решение (алгоритм) будет использоваться в каждом целевом языке, хотя в действительности различия между ними могут означать, что это невозможно / не очень хорошая идея.
Возможно, кто-то здесь мог бы указать мне на менее пешеходные способы достижения этой цели — то есть не только на порты array_diff.
Вот эквивалент решения array_diff: (при условии, что я не ошибся)
package main
import "fmt"
func FindLeastDifferent(needle []float64, haystack [][]float64) int {
if len(haystack) == 0 {
return -1
}
var currentIndex, currentDiff int
for i, arr := range haystack {
diff := 0
for j := range needle {
if arr[j] != needle[j] {
diff++
}
}
if i == 0 || diff < currentDiff {
currentDiff = diff
currentIndex = i
}
}
return currentIndex
}
func main() {
idx := FindLeastDifferent(
[]float64{2.05080E6, 29400, 420},
[][]float64{
{2.05080E6, 29400, 0},
{2.05080E6, 9800, 420},
{1.715E6, 24500, 280},
{2.05080E6, 29400, 140},
{2.05080E6, 4900, 7},
{2.05080E6, 29400, 420},
},
)
fmt.Println(idx)
}
Как вы сказали, это O(n * m)
где n
число элементов в массиве игл, и m
количество массивов в стоге сена
Если вы заранее не знаете стог сена, то, вероятно, вы мало что можете сделать, чтобы улучшить это. Но если вместо этого вы храните этот список в базе данных, я думаю, что ваша интуиция о поиске строк имеет некоторый потенциал. PostgreSQL, например, поддерживает индексы сходства строк. (И вот объяснение аналогичной идеи для регулярных выражений: http://swtch.com/~rsc/regexp/regexp4.html)
Еще одна идея: если ваши массивы действительно большие, вы можете вычислить нечеткие хеши (http://ssdeep.sourceforge.net/) который бы сделал ваш n
меньше.
Других решений пока нет …