Matlab生成符合规则的词表排列问题求助
问题:生成符合规则的词表随机排列(Matlab实现)
需求说明
- 词表共12个条目,分4个语义类别,每类3个:
- 家具类:
couch、shelf、table - 交通工具类:
plane、boat、truck - 服饰类:
Jacket、shoes、sweater - 蔬菜类:
lettuce、carrot、spinach
- 家具类:
- 排列规则:
- 同一语义类别的条目不能相邻
- 排列分为3个区块(第1-4项、5-8项、9-12项),每个区块中每个语义类别恰好出现1次
用户问题
编程新手,仅了解排列计算,无法将已有Python方案转换为Matlab代码,自行编写的Matlab代码陷入死循环,需手动暂停。
用户错误代码
% Wordlist wordlist = {'Carrot', 'Spinach', 'Lettuce', 'Jacket', 'Shoes', 'Sweater', 'Plane', 'Boat', 'Truck', 'Shelf', 'Table', 'Couch'}; % Define semantic categories categories = {'Vegetables', 'Clothing', 'Vehicles', 'Furniture'}; while true % Shuffle indices shuffled_indices = randperm(length(wordlist)); % Check semantic relatedness and ensure no two related items neighbor each other no_neighboring_related = all(arrayfun(@(i) ~any(ismember(wordlist(shuffled_indices(i:i+1)), categories)), 1:length(shuffled_indices)-1)); % Check representation in each block representation_in_blocks = all(arrayfun(@(a) numel(unique(wordlist(shuffled_indices(a:a+3)))) == 4 && ... all(ismember(categories, wordlist(shuffled_indices(a:a+3)))), [1, 5, 9])); % If both conditions are met, break out of the loop if no_neighboring_related && representation_in_blocks break; end end % Display the randomly generated wordlist disp('Randomly Generated Wordlist:'); disp(wordlist(shuffled_indices));
错误原因分析
- 类别匹配逻辑完全错误:
categories存储的是类别名称(如Vegetables),但wordlist里是具体条目(如Carrot),ismember(wordlist(...), categories)永远返回假,导致第一个条件no_neighboring_related恒为真,失去校验意义。 - 区块校验逻辑错误:
numel(unique(wordlist(...))) ==4只能保证区块内4个条目不重复,但无法保证每个类别各占1个(比如可能出现2个蔬菜+1个服饰+1个交通工具)。all(ismember(categories, wordlist(...)))同样是类别名称和具体条目匹配,永远为假,导致representation_in_blocks恒为假,循环永远无法退出。
- 随机乱碰效率极低:符合条件的排列占比极低,纯随机生成再校验的方式几乎不可能命中,必然陷入死循环。
正确实现方案
采用构造式生成,先按区块分配每个类别的条目,再确保相邻条目不同类别:
% 1. 按类别整理词表,每个类别对应3个条目 category_words = struct(... 'Vegetables', {'Carrot', 'Spinach', 'Lettuce'}, ... 'Clothing', {'Jacket', 'Shoes', 'Sweater'}, ... 'Vehicles', {'Plane', 'Boat', 'Truck'}, ... 'Furniture', {'Shelf', 'Table', 'Couch'}); category_names = fieldnames(category_words); num_categories = length(category_names); num_blocks = 3; % 2. 为每个区块分配每个类别的条目(每个类别3个条目,3个区块各用1个) block_assignments = cell(num_blocks, num_categories); for cat_idx = 1:num_categories % 打乱当前类别的条目,分配给3个区块 shuffled_cat = category_words.(category_names{cat_idx})(randperm(3)); for block_idx = 1:num_blocks block_assignments(block_idx, cat_idx) = shuffled_cat(block_idx); end end % 3. 生成符合条件的排列 while true final_list = {}; prev_category = ''; % 记录上一个条目所属类别 valid = true; for block_idx = 1:num_blocks % 打乱当前区块的4个条目(来自不同类别) shuffled_block = block_assignments(block_idx, randperm(num_categories)); % 检查区块第一个条目是否和上一个区块最后一个条目同类别 if ~isempty(prev_category) current_first_cat = find(strcmp(category_names, get_category(shuffled_block{1}, category_words))); if current_first_cat == prev_category % 重新打乱区块,直到第一个条目类别不同 while current_first_cat == prev_category shuffled_block = block_assignments(block_idx, randperm(num_categories)); current_first_cat = find(strcmp(category_names, get_category(shuffled_block{1}, category_words))); end end end % 将区块加入最终列表,更新上一个类别 final_list = [final_list, shuffled_block]; prev_category = find(strcmp(category_names, get_category(shuffled_block{end}, category_words))); end % 最终检查所有相邻条目是否不同类别(保险) for i = 1:length(final_list)-1 cat_i = get_category(final_list{i}, category_words); cat_i1 = get_category(final_list{i+1}, category_words); if strcmp(cat_i, cat_i1) valid = false; break; end end if valid break; end end % 输出结果 disp('Randomly Generated Wordlist:'); disp(final_list); % 辅助函数:根据条目返回所属类别 function cat_name = get_category(word, category_words) cat_fields = fieldnames(category_words); for idx = 1:length(cat_fields) if ismember(word, category_words.(cat_fields{idx})) cat_name = cat_fields{idx}; return; end end cat_name = ''; end
代码说明
- 类别整理:用结构体存储每个类别对应的条目,方便后续查询和分配。
- 区块条目分配:每个类别下的3个条目随机分配给3个区块,确保每个区块从每个类别各取1个。
- 区块打乱与衔接校验:每个区块内部随机打乱(因条目来自不同类别,内部自然无同类别相邻),重点校验区块之间的衔接条目是否同类别,若有则重新打乱当前区块。
- 最终校验:遍历整个列表,确保所有相邻条目不同类别,避免极端情况。
内容的提问来源于stack exchange,提问作者Rory Holden
相关产品推荐
相关产品推荐

