Есть ли более элегантный способ выражения следующего кода (например, без явного цикла for)?
P = [0.1 0.2 0.3 0.4];
% pre-allocate symbols array of struct
symbols = repmat(struct('probability', 0, 'indices', []), length(P), 1);
for i =1:length(P)
symbols(i) = struct('probability', P(i), 'indices', i);
end
P.S .: Я использую символы для реализации кодирования Хаффмана, если кому-то интересно.
Редактировать: Вдохновленный одним из комментариев, я мог бы просто сделать это
P = [0.1 0.2 0.3 0.4];
symbols = [
[0.1 1];
[0.2 2];
[0.3 3];
[0.4 4];
];
% access probability:
symbols(i)(1)
% access indices:
symbols(i)(2:end)
So
symbols = [P(:) (1:length(P))']
Edit2: Для полноты, вот весь код, который я использую (код Хаффмана)
function [c,h,w]=huffman(P)
assert(abs(sum(P) - 1) < 10e-6, "Probabilities must sum up to 100%");
% compute entropy
h = sum(P .* (-log2(P)));
% each row corresponds to the probability in P
c = cell(length(P), 1); % codes are represent as numerical vectors for bits
P = sort(P, 'descend');
% Preallocate 'symbols' for each probability
% A symbol is used to represent dummy "fused" probabilities as well
% size(symbols) == 1xlength(P) initially
% IMPORTANT: sort P first descending
symbols = struct('probability', num2cell(P), 'indices', num2cell(1:length(P)));
%symbols = repmat(struct('probability', 0, 'indices', []), length(P), 1);
%for i =1:length(P)
% symbols(i) = struct('probability', P(i), 'indices', i);
%end
while length(symbols) > 1
% select the two lowest probabilities and add them
% O(n) insert worst case vs log(n) binary search...
last = symbols(end);
preLast = symbols(end-1);
% Build the code words by prepending bits
c(last.indices) = cellfun(@(x)[0 x], c(last.indices), 'UniformOutput', false);
c(preLast.indices) = cellfun(@(x)[1 x], c(preLast.indices), 'UniformOutput', false);
% Insert dummy symbol representing combined probability of the two
% lowest probabilities
probSum = last.probability + preLast.probability;
newSymbol = struct('probability', probSum, 'indices', [last.indices preLast.indices]);
pos = find([symbols.probability] < probSum, 1);
% insert dummy symbol and remove the two symbols which belong to it
symbols = [symbols(1:pos-1) newSymbol symbols(pos:end-2)];
end
assert(length(symbols) == 1 && abs(symbols(1).probability - 1) < 10e-6, "Probability of tree root must add up to 100%");
% compute average codeword length
w = sum(cellfun('length', c) .* P(:));
Я думаю, что использование числовых массивов вместо структур и сохранение 0 в качестве «без индекса» - это больше работы, потому что я должен убедиться, что все индексные массивы заполнены нулями должным образом, и вызвать find (индексы> 0) перед их использованием. Поэтому я пока пропущу это.
Это примерно в 3 раза быстрее, чем какой-то случайный код Я нашел в интернете, так что это не может быть ужасно.
Редактировать 3: По сути, это примерно на 40% быстрее, чем хаффмандикт из набора инструментов систем связи, так что да, вот и все. Либо я что-то упустил, либо они не заботятся о производительности.