You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何筛选满足首元素出现顺序条件的数组多重排列?

解决方案

要筛选出符合要求的排列,需同时满足两个核心条件:0、1、2、3的首次出现顺序严格遵循0→1→2→3,以及每个数字的第二次出现位置在其首次出现位置右侧(注:multiset_permutations生成的排列天然满足第二个条件,代码中保留判断以确保严谨性)。

方法一:逐行循环判断(易理解)

逻辑直观,适合小数据量场景:

import numpy as np
from sympy.utilities.iterables import multiset_permutations

# 生成所有排列
a = np.array([0, 0, 1, 1, 2, 2, 3, 3])
out = np.array(list(multiset_permutations(a)))

# 定义验证函数
def is_valid(p):
    # 检查首次出现顺序
    first_idx = [np.argmax(p == x) for x in [0,1,2,3]]
    if not (first_idx[0] < first_idx[1] < first_idx[2] < first_idx[3]):
        return False
    # 检查第二次出现位置在首次之后
    for x in [0,1,2,3]:
        pos = np.where(p == x)[0]
        if pos[1] <= pos[0]:
            return False
    return True

# 筛选有效排列
valid_perms = out[np.array([is_valid(row) for row in out])]

代码说明:

  • np.argmax(p == x):找到数字x在排列中首次出现的索引(布尔数组的第一个True位置)。
  • 首次出现顺序判断:确保0的首次位置早于1,1早于2,2早于3。
  • 第二次出现位置判断:通过np.where获取数字x的所有出现位置,验证第二个位置索引大于第一个。

方法二:向量化批量处理(高效)

当排列数量较大(比如5对数字时总排列数达113400),用numpy向量化操作可大幅提升效率:

import numpy as np
from sympy.utilities.iterables import multiset_permutations

a = np.array([0, 0, 1, 1, 2, 2, 3, 3])
out = np.array(list(multiset_permutations(a)))

# 目标数字列表(扩展到5对时改为[0,1,2,3,4])
targets = np.array([0,1,2,3])

# 1. 计算每一行中每个目标数字的首次出现索引
matches = out[:, None] == targets[None, :, None]  # 广播为(N,4,8)的布尔数组
first_occur = matches.argmax(axis=2)  # (N,4),每行对应4个数字的首次索引

# 2. 验证首次出现顺序严格递增
cond1 = (first_occur[:,0] < first_occur[:,1]) & (first_occur[:,1] < first_occur[:,2]) & (first_occur[:,2] < first_occur[:,3])

# 3. 验证每个数字的第二次出现位置在首次之后
last_occur = matches.cumsum(axis=2).argmax(axis=2)  # 计算最后出现索引(即第二次出现位置)
cond2 = (last_occur > first_occur).all(axis=1)  # 所有数字的最后位置都大于首次位置

# 4. 筛选有效排列
valid_mask = cond1 & cond2
valid_perms = out[valid_mask]

代码说明:

  • 广播匹配:通过out[:, None] == targets[None, :, None]一次性对比所有行与所有目标数字的匹配情况,避免循环。
  • 首次/最后出现索引:argmax(axis=2)找首次匹配位置;cumsum(axis=2).argmax(axis=2)通过累计求和找到最后一次匹配的位置(即第二次出现的索引)。
  • 条件合并:用布尔掩码批量筛选所有符合条件的排列,效率远高于逐行循环。

扩展到5对数字的场景

只需将代码中的targets改为np.array([0,1,2,3,4]),并调整cond1的判断逻辑为:

cond1 = (first_occur[:,0] < first_occur[:,1]) & (first_occur[:,1] < first_occur[:,2]) & (first_occur[:,2] < first_occur[:,3]) & (first_occur[:,3] < first_occur[:,4])

其余代码无需修改即可直接使用。

内容的提问来源于stack exchange,提问作者user109387

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 09:46:05