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

如何打乱数组但保留指定元素位置?播放列表固定Jingle需求

仅打乱播放列表中普通曲目,保留固定广告曲位置的实现方案

给定一个混合了固定广告曲(标题为jingle fixed)和普通曲目的播放列表数组,现有洗牌函数会打乱所有元素位置,但我们需要保持广告曲的位置完全不变,仅随机打乱普通曲目的顺序。

原代码示例

var arr = [         
    {'title': 'jingle fixed'},
    {'title': 'track 0'},
    {'title': 'track 1'},
    {'title': 'jingle fixed'},
    {'title': 'track 2'},
    {'title': 'jingle fixed'},
    {'title': 'track 3'},
    {'title': 'track 4'},
    {'title': 'track 5'}
];

function shuffle(playList) {
    let currentIndex = playList.length, randomIndex;
    
    while (currentIndex != 0) { 
        randomIndex = Math.floor(Math.random() * currentIndex);
        currentIndex--;

        // How to except by playList.title?
        [playList[currentIndex], playList[randomIndex]] = [playList[randomIndex], playList[currentIndex]];
    }
  
    return playList;
}

解决方案

核心思路是:先提取所有普通曲目并洗牌,再遍历原数组保留广告曲位置,替换为洗牌后的普通曲目。

function shuffleOnlyTracks(playList) {
    // 提取所有非广告曲目
    const tracks = playList.filter(item => item.title !== 'jingle fixed');
    
    // 使用Fisher-Yates洗牌算法打乱曲目(公平无偏的洗牌方式)
    let currentIndex = tracks.length;
    while (currentIndex > 0) {
        const randomIndex = Math.floor(Math.random() * currentIndex);
        currentIndex--;
        [tracks[currentIndex], tracks[randomIndex]] = [tracks[randomIndex], tracks[currentIndex]];
    }

    // 遍历原列表,保留广告曲位置,替换为打乱后的曲目
    let trackPointer = 0;
    return playList.map(item => {
        return item.title === 'jingle fixed' ? item : tracks[trackPointer++];
    });
}

// 调用测试
const result = shuffleOnlyTracks(arr);
console.log(result);

说明

  1. 提取并洗牌曲目:先筛选出所有非jingle fixed的元素,用Fisher-Yates算法洗牌,这是业界公认的公平洗牌方式,避免了sort(() => Math.random() - 0.5)存在的概率偏斜问题。
  2. 保留广告曲位置:遍历原数组时,遇到广告曲直接返回原元素,遇到普通曲目则从洗牌后的列表中按顺序取出替换,完美保留了广告曲的原始位置。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 15:51:54