2017-02-14 3 views
0

Я знаю, что есть функция, которая делает это, например:Найти индексы ненулевых элементов из [1,2,0,0,4,0] в Джулию и создать Arrray с ними

A = [1,2,0,0,4,0] 
find(A) 

3-element Array{Int64,1}: 
1 
2 
5 

Я пытаюсь сделать это по-своему, однако, я застрял здесь

for i=1:endof(A) 
    if A[i] != 0 
     [] 
    end 
end 

Спасибо заранее.

+2

Можете ли вы объяснить немного больше, где ваша проблема? Вы ищете 'push!'? Вы также можете посмотреть исходный код 'find' с' @less find (A) '. – tim

+3

Я скорее желаю, чтобы сообщество было менее поспешным, чтобы опустить новых членов. @ user7546279, выберите прозвище, и мы будем любить вас больше. И проверьте https://gitter.im/JuliaLang/julia –

+1

'B = A [A.! = 0]' также работает (спасибо @ Ismael-VC) –

ответ

4

Вот одна альтернатива:

function myfind(c) 
    a = similar(c, Int) 
    count = 1 
    @inbounds for i in eachindex(c) 
     a[count] = i 
     count += (c[i] != zero(eltype(c))) 
    end 
    return resize!(a, count-1) 
end 

Это фактически превзошла find для всех случаев, которые я тестировал, хотя для очень небольшой пример вектора вы в курсе, разница была незначительной. Возможно, есть преимущество в производительности, чтобы избежать ветвления и динамически увеличивать индексный массив.

+0

вы можете вызвать 'countnz' в массиве' a', чтобы получить номер 'n' ненулевых элементов в массиве, а затем предварительно распределить' a' с правильным размером. –

+0

Несомненно, но тогда вам нужно пройти через массив дополнительное время, которое, похоже, потрачено впустую. Это будет в два раза больше работы. – DNF

+0

Я предполагаю, что это зависит от конкретного аспекта производительности, который вы хотите оптимизировать. мое предложение отражает мое предпочтение минимизации транзакций памяти. 'countnz' не выделяет память, и для ее использования в prealocate' a' используется только необходимая память. –

2

Я заметил, что вопрос действительно путается (потому что плохо сформулирован, извините за это). Поэтому есть два возможных ответа: один - [1,2,4], который представляет собой массив с ненулевыми элементами; другой - [1,2,5], который является массивом индексов ненулевых элементов.

Давайте начнем с первого варианта

A = [1,2,0,0,4,0] 
B = [] 

for i=1:endof(A) 
    if A[i] != 0 
     push!(B,i) 
    end 
end 
println(B) 

Выход Any[1,2,5]

Однако тип не один я хотел. Использование typeof(B) это показывает Array{Any,1}, поэтому я добавил этот код:

B = Array{Int64}(B) 
println(B) 
typeof(B) 

И результат желаемой

[1,2,5] 
Array{Int64,1} 

Для повышения его эффективности, следуя рекомендации в комментариях, я указал тип Б с функцией eltype() до того, как цикл следующим образом:

A1 = [1,2,0,0,4,0] #The default type is Array{Int64,1} 
B1 = eltype(A1)[] #Define the type of the 0 element array B with the type of A 
#B1 = eltype(typeof(A))[] this is also valid 
for i=1:endof(A1) 
    if A1[i] != 0 
     push!(B1::Array{Int64,1},i::Int64) 
    end 
end 
println(B1) 
typeof(B1) 

Затем выходной сигнал снова желаемый

[1,2,5] 
Array{Int64,1} 

Простейший способ сделать это - использовать функцию find(). Однако, поскольку я начинающий, я хотел сделать это по-другому. Однако есть еще одна альтернатива, предоставляемая @DNF, которая превосходит find() для случаев, которые он протестировал (см. Ниже ответы).

Второй вариант, который создает матрицу вывода с ненулевыми элементами, был предоставлен другими пользователями (@Harrison Grodin и @P i) в этом обсуждении.

Спасибо всем вам за помощь!

+3

Чтобы получить правильный тип с самого начала, вы можете использовать 'B = eltype (A) []'. В конце концов посмотрите http://docs.julialang.org/en/release-0.5/manual/performance-tips/. В частности, делать вещи в глобальном масштабе медленны. – tim

+0

Еще раз спасибо, эти вещи мне очень помогают. – Pau

+2

Обратите внимание, что вам не нужно переназначать результат 'push! (B, ...)' back to 'B'. Что '!' означает, что первый параметр изменен. –

2

У вас есть несколько вариантов здесь.

С помощью стратегии, которую вы начали использовать, вы можете использовать push! внутри цикла for.

julia> B = Int[] 
0-element Array{Int64,1} 

julia> for element = A 
      if element != 0 
       push!(B, element) 
      end 
     end 

julia> B 
3-element Array{Int64,1}: 
1 
2 
4 

Вы также можете выбрать использование оценки короткого замыкания.

julia> for element = A 
      element != 0 && push!(B, element) 
     end 

julia> for element = A 
      element == 0 || push!(B, element) 
     end 

Оба filter и списочные действительны, как хорошо!

julia> B = [element for element = A if element != 0] 
3-element Array{Int64,1}: 
1 
2 
4 

julia> filter(n -> n != 0, A) 
3-element Array{Int64,1}: 
1 
2 
4 

Edit: Благодаря замечанием OP, я понял, что желаемый результат является индексы ненулевых элементов, а не сами элементы. Этого можно добиться просто следующим образом. :)

julia> find(A) 
3-element Array{Int64,1}: 
1 
2 
5 
+0

Дело в том, что я заметил, что вопрос не слишком ясен. Я хочу массив, содержащий индексы ненулевых элементов, а не массив ненулевых элементов. Однако, большое спасибо! это так полезно. – Pau

+1

@Pau Ах, я вижу! Я обновил свой ответ, чтобы включить решение для поиска индексов. Надеюсь, это поможет! :) –