Как присвоить значение матричному элементу, который удовлетворяет определенному условию? - PullRequest
1 голос
/ 29 октября 2019

Мне нужно создать новую матрицу из матрицы A. Все элементы в новой матрице должны быть элементами из матрицы A, кроме элементов на главной диагонали. Нечетные элементы на главной диагонали должны быть разделены на 2, а четные элементы на главной диагонали должны быть умножены на 3.

julia> A=rand(1:10 ,3,3)
3×3 Array{Int64,2}:
  5  3  1
  5  2  6
 10  1  7

Я решил создать новую матрицу из двух матриц. Во-первых, я решил сохранить все элементы матрицы A, кроме элементов на главной диагонали, в матрице B с нулями на главной диагонали:

julia> B=A .* .~ I(3)
3×3 Array{Int64,2}:
  0  3  1
  5  0  6
 10  1  0

Затем я хотел создать матрицу C с такой же главной диагональю. как A, а все остальные элементы - нули:

julia> C=A .* one(A)
3×3 Array{Int64,2}:
  5  0  0
  0  2  0
  0  0  7

Наконец, моя цель состояла в том, чтобы внести все изменения в матрицу C и затем создать окончательную матрицу как

D = C + B;

У меня проблема с внесением изменений на главной диагонали, потому что я не уверен , как присвоить значение матричным элементам, которые удовлетворяют определенному условию . Например, как умножить четные элементы на главной диагонали на 3 и разделить нечетные элементы на главной диагонали на 2?

Я попытался использовать replace: replace!(x->x%2!=0 ? x/2 : x, C), но он возвращает ошибку. Я пытался использовать C[C .% 2 .!=0], а потом что-то делал с этим, но не смог сделать это правильно.

Заранее спасибо!

Ответы [ 2 ]

2 голосов
/ 29 октября 2019

как насчет простого цикла?

function change_diagonal!(A)
    @inbounds for i = 1:size(A,1)
        if iseven(A[i,i])
            A[i,i] = 3*A[i,i]
        else
            A[i,i] = A[i,i]/2
        end
    end
    return A
end

Одна проблема с этим заключается в том, что ваша матрица имеет тип Int64, и деление нечетного числа на два не дает целого числа. но, в общем, если вы хотите выполнить операцию только над основными элементами плотной матрицы, простой цикл будет простым и быстрым. важно отметить, что это изменяет матрицу на месте, поэтому при выполнении операции не выделяется никакой памяти. Если мы расширим это, чтобы сделать его более общим:

function change_diagonal!(f,A)
    @inbounds for i = 1:size(A,1)
        A[i,i] = f(A[i,i]) 
    end
    return A
end

Вы можете передать любую функцию иэта функция будет отображаться на диагональных элементах вашей матрицы.

РЕДАКТИРОВАТЬ: есть другой способ, я не знаю, если быстрее (вероятно, нет), но ради полноты, здесь егоИдея: вы можете сгенерировать вектор, который соответствует виду диагонали матрицы, поэтому при изменении этого вектора вы изменяете исходную матрицу. вот функция, которая генерирует это представление:

function diagonal_view(A)
    return @view A[diagind(A)]
end

теперь вы можете работать с диагональю, как если бы это был простой вектор:

A = rand(1.0:10.0,5,5)
diagA = diagonal_view(A)
diagA .= 40.0 #all elements of the diagonal of A are changed to 40.0
map!(x->2x,diagA,diagA) # another way to modify the diagonal, doubles the values
1 голос
/ 29 октября 2019

Проблема в том, что матрица A имела тип Int64, и деление нечетного числа на два не дает целого числа. Если вы разделите нечетное число на два, результатом будет не Int64, (7/2) = 3,5. Ключ должен был изменить генерацию матрицы на A=rand(1.0:10.0 , 3,3), а затем replace!(x->x%2!=0 ? x/2 : x, C) и replace!(x->x%2==0 ? x*3 : x, C) работали отлично!

Большое спасибо @ longemen3000 за указание на это!

...