グループ数:最大5
各グループの要素数:最大20
各グループから1つずつ選択
グループ数は可変(1~5)
値は cell 配列で渡される
下位グループの要素数は上位グループを超えない
(例:G1=20個なら G2~G5は20個以下)
組み合わせ数を求める関数
function nComb = countCombination(groups)
% 空グループ除外
groups = groups(~cellfun('isempty',groups));
if isempty(groups)
nComb = 0;
return;
end
nComb = prod(cellfun(@numel, groups));
end
全組み合わせを生成する関数
function comb = makeCombination(groups)
% 空グループ除外
groups = groups(~cellfun('isempty',groups));
nGroup = numel(groups);
if nGroup == 0
comb = [];
return;
end
% 各グループの添字
idx = cell(1,nGroup);
for k = 1:nGroup
idx{k} = 1:numel(groups{k});
end
% 全組み合わせの添字生成
G = cell(1,nGroup);
[G{:}] = ndgrid(idx{:});
nComb = numel(G{1});
comb = zeros(nComb,nGroup);
for k = 1:nGroup
comb(:,k) = groups{k}(G{k}(:));
end
end
同一グループが複数ある場合
groups = {
[10 20 30 40]
[50 60]
[70 80]
[90 100]
[110 120]
};
groupId = {
'G1'
'G2'
'G2'
'G3'
'G4'
};
[comb,nComb] = makeCombination(groups,groupId);
function [comb,nComb] = makeCombination(groups,groupId)
% グループ統合
uGroup = unique(groupId,'stable');
mergedGroups = cell(1,numel(uGroup));
for k = 1:numel(uGroup)
idx = strcmp(groupId,uGroup{k});
tmp = [];
for m = find(idx(:))'
tmp = [tmp groups{m}];
end
mergedGroups{k} = unique(tmp,'stable');
end
% 空グループ除外
mergedGroups = mergedGroups(~cellfun(@isempty,mergedGroups));
nGroup = numel(mergedGroups);
nElem = cellfun(@numel,mergedGroups);
nComb = prod(nElem);
% 添字生成
idx = cell(1,nGroup);
for k = 1:nGroup
idx{k} = 1:nElem(k);
end
[grid{1:nGroup}] = ndgrid(idx{:});
comb = zeros(nComb,nGroup);
for k = 1:nGroup
comb(:,k) = mergedGroups{k}(grid{k}(:));
end
end
結果を縦横並び替える
C = num2cell(comb);
C = C.';
または1行で
C = num2cell(comb).';
app.UITable.Data = num2cell(comb);
もしくは
app.UITable.Data = num2cell(comb).';
cellから値を変えるなら
cell2mat
■その2
function result = makeCombination(C)
%----- グループ番号取得 -----
grp = cell2mat(C(:,1));
uGrp = unique(grp,'stable');
%----- グループごとの候補作成 -----
groupData = cell(numel(uGrp),1);
for g = 1:numel(uGrp)
rows = find(grp==uGrp(g));
if numel(rows)==1
vals = {};
for c = 2:size(C,2)
if isempty(C{rows,c})
break
end
vals{end+1} = C{rows,c};
end
groupData{g} = vals;
else
% 同一グループ複数行
maxCol = 0;
for r = rows(:)'
lastCol = find(~cellfun(@isempty,...
C(r,2:end)),1,'last');
maxCol = max(maxCol,lastCol);
end
tmp = cell(1,maxCol);
for k = 1:maxCol
x = cell(numel(rows),1);
for r = 1:numel(rows)
x{r} = C{rows(r),k+1};
end
tmp{k} = x;
end
groupData{g} = tmp;
end
end
%----- 組み合わせ数 -----
nChoice = cellfun(@numel,groupData);
combCount = prod(nChoice);
fprintf('Combination Count = %d\n',combCount);
%----- ndgrid -----
idx = cell(1,numel(groupData));
for k = 1:numel(groupData)
idx{k} = 1:nChoice(k);
end
[G{1:numel(groupData)}] = ndgrid(idx{:});
%----- 結果作成 -----
rowCount = 0;
for g = 1:numel(groupData)
if iscell(groupData{g}{1})
rowCount = rowCount + numel(groupData{g}{1});
else
rowCount = rowCount + 1;
end
end
result = cell(rowCount,combCount);
for col = 1:combCount
rOut = 1;
for g = 1:numel(groupData)
sel = G{g}(col);
value = groupData{g}{sel};
if iscell(value)
for k = 1:numel(value)
result{rOut,col} = value{k};
rOut = rOut + 1;
end
else
result{rOut,col} = value;
rOut = rOut + 1;
end
end
end
end
使用例
C = {
1 10 20 30 40 []
2 50 60 [] [] []
2 70 80 [] [] []
3 90 100 [] [] []
4 110 120 [] [] []
5 130 140 [] [] []
};
result = makeCombination(C);
writematrix(cell2mat(result),'result.xlsx');
■その2
function [result, combCount] = makeGroupCombination(inputCell)
% inputCell:
% 1列目 : グループ番号
% 2列目~ : 値
% 空セル以降は値なし
%
% result:
% 行 : 入力行
% 列 : 組み合わせ
%
% 同一グループの複数行は、同じ選択肢番号で連動する。
% 同一グループ内で値数が異なる場合、短い行は先頭から繰り返す。
%% 入力チェック
if isempty(inputCell) || size(inputCell,2) < 2
error('inputCellは、グループ番号列と値列を含めてください。');
end
groupNo = cell2mat(inputCell(:,1));
if any(~isfinite(groupNo)) || any(groupNo ~= fix(groupNo))
error('1列目のグループ番号は整数にしてください。');
end
if any(groupNo < 1) || any(groupNo > 5)
error('グループ番号は1~5にしてください。');
end
uniqueGroup = unique(groupNo,'stable');
% グループ番号が 1,2,3,... と連続しているか確認
if ~isequal(uniqueGroup, 1:numel(uniqueGroup))
error(['グループ番号は連続して指定してください。' newline ...
'例:グループ1の次にグループ3だけを指定することはできません。']);
end
%% 各入力行の値を取り出す
nInputRow = size(inputCell,1);
rowValues = cell(nInputRow,1);
rowValueCount = zeros(nInputRow,1);
for r = 1:nInputRow
values = {};
for c = 2:size(inputCell,2)
% 空セル以降は値なし
if isempty(inputCell{r,c})
break;
end
values{end+1} = inputCell{r,c};
end
if isempty(values)
error('入力%d行目に値がありません。', r);
end
rowValues{r} = values;
rowValueCount(r) = numel(values);
end
%% 各グループの選択肢数
nGroup = numel(uniqueGroup);
groupChoiceCount = zeros(1,nGroup);
for g = 1:nGroup
rows = find(groupNo == uniqueGroup(g));
% 同一グループ内で最大の値数を選択肢数とする
groupChoiceCount(g) = max(rowValueCount(rows));
end
%% 組み合わせ数
combCount = prod(groupChoiceCount);
%% 各グループの選択番号を作る
indexCell = cell(1,nGroup);
for g = 1:nGroup
indexCell{g} = 1:groupChoiceCount(g);
end
gridCell = cell(1,nGroup);
[gridCell{:}] = ndgrid(indexCell{:});
%% 結果作成
result = cell(nInputRow,combCount);
for r = 1:nInputRow
% この入力行が属するグループの位置
groupIndex = find(uniqueGroup == groupNo(r), 1);
% そのグループの選択番号
selectedIndex = gridCell{groupIndex}(:);
nValue = numel(rowValues{r});
for col = 1:combCount
% 値数を超えたら先頭へ戻る
valueIndex = mod(selectedIndex(col)-1, nValue) + 1;
result{r,col} = rowValues{r}{valueIndex};
end
end
end