2016-04-01 4 views
3

В Юле мы можем проверить, если массив содержит значение, например так:Джулии: это массив содержит конкретный вложенный массив

> 6 in [4,6,5] 
true 

Однако это возвращает ложь, при попытке проверить наличие подрешетки в определенном порядке:

> [4,6] in [4,6,5] 
false 

Что такое правильный синтаксис, чтобы проверить, если конкретный суб-массив существует в массиве?

+0

Второй результат в вопросе не соответствует его описанию. Это кортеж «4» и первый результат. –

+0

исправлено, Исправлено: –

+0

Пакет [Iterators.jl] (https://github.com/JuliaLang/Iterators.jl) также предоставляет полезную функцию 'subsets', и вы можете написать' [4,6] в подмножествах ([ 4,5,6]) '. – Gnimuc

ответ

3

Для т.е. вектора третьего состояния [4,6] появляется как суб-вектор 4,6,5 следующая функция предлагается:

issubvec(v,big) = 
    any([v == slice(big,i:(i+length(v)-1)) for i=1:(length(big)-length(v)+1)]) 

Для второго условия, то есть, дать логический для каждого элемента в els векторах, появляется в set векторе, следующее предлагается:

function vecin(els,set) 
    res = zeros(Bool,size(els)) 
    res[findin(els,set)]=true 
    res 
end 

с вектором в ОП, эти результаты:

julia> vecin([4,6],[4,6,5]) 
2-element Array{Bool,1}: 
true 
true 

julia> issubvec([4,6],[4,6,5]) 
true 
+1

issubvec возвращает правильный результат, но также не очень эффективен, потому что он делает много распределений. Рекомендуется использовать '@ time', чтобы увидеть, как производительность страдает из-за чрезмерных распределений. –

+1

'issubvec', безусловно, неоптимизирован, @ScottJones, но его логика очень ясна - это было моим намерением. Функция, которую вы написали, лучше (и существуют еще более оптимизированные алгоритмы поиска подстрок/подвекторов). Я думаю, что такие общие функции подвекторов могут поместиться в Base (с похожими именами на строковые функции). –

+0

На самом деле мне пришлось бороться с логикой 'issubvec', с комбинацией понимания массива и использования функций' slice' и 'any'. Это не значит, что я критикую, мне нравится видеть мощные вещи, которые могут быть выполнены с помощью функций массива Джулии, но из C/C++/Java и т. Д. Мне пришлось крутить мой мозг, чтобы понять это.Кроме того, я видел, что короткий сладкий код, подобный этому, часто не масштабируется, а я парень производительности –

5

Это занимает немного кода, чтобы сделать функцию, которая выполняет хорошо, но это намного быстрее, чем версия выше issubvec:

function subset2(x,y) 
    lenx = length(x) 
    first = x[1] 
    if lenx == 1 
     return findnext(y, first, 1) != 0 
    end 
    leny = length(y) 
    lim = length(y) - length(x) + 1 
    cur = 1 
    while (cur = findnext(y, first, cur)) != 0 
     cur > lim && break 
     beg = cur 
     @inbounds for i = 2:lenx 
      y[beg += 1] != x[i] && (beg = 0 ; break) 
     end 
     beg != 0 && return true 
     cur += 1 
    end 
    false 
end 

Примечание: также было бы гораздо полезнее, если функция фактически вернула позицию начала подмассива, если она найдена, или 0, если нет, аналогично функциям findfirst/findnext.

информация Timing (второй использует свою функцию subset2):

0.005273 seconds (65.70 k allocations: 4.073 MB) 
    0.000086 seconds (4 allocations: 160 bytes) 
+0

Первый результат '@ time' (для' issubvec') выглядит так, будто он может включать компиляцию - это слишком много для такого простого вызова. Можете ли вы перепроверить (с запуском компиляции перед синхронизацией)? –

+0

Не вышло - я, конечно, скомпилирован перед запуском (без макроса @time). Я также тестировал различные длины, которые я показал, тестировал вектор длиной 64 К, ища последовательность из 4 (последние 4 значения в векторе). Кажется, что 'issubvec' имеет O (n) распределения, где n - длина y. –

+0

OK. Важен тест. Если вы добавите код тестового запуска точно, я могу увидеть, может ли быть полезным использование Julia 0.5 против 0.4. –

1

Я использовал это в последнее время, чтобы найти подпоследовательности в массивы целых чисел. Это не так хорошо или быстро, как @ scott's subset2(x,y) ... но он возвращает индексы.

function findsequence(arr::Array{Int64}, seq::Array{Int64}) 
    indices = Int64[] 
    i = 1 
    n = length(seq) 
    if n == 1 
     while true 
      occurrence = findnext(arr, seq[1], i) 
      if occurrence == 0 
       break 
      else 
       push!(indices, occurrence) 
       i = occurrence +1 
      end 
     end 
    else 
     while true 
      occurrence = Base._searchindex(arr, seq, i) 
      if occurrence == 0 
       break 
      else 
       push!(indices, occurrence) 
       i = occurrence +1 
      end 
     end 
    end 
    return indices 
end 

julia> @time findsequence(rand(1:9, 1000), [2,3]) 
    0.000036 seconds (29 allocations: 8.766 KB) 
    16-element Array{Int64,1}: 
    80 
    118 
    138 
    158 
    234 
    243 
    409 
    470 
    539 
    589 
    619 
    629 
    645 
    666 
    762 
    856 
+1

Да, это очень полезно. Я также не знал о Base._searchindex, мне придется сравнивать его! Я думаю, что итератор был бы хорош, чтобы не создавать потенциально большой вектор (может быть до длины seq). –

Смежные вопросы