从多个其他列表中创建n项长播放列表式列表

时间:2017-07-05 19:56:12

标签: python list numpy

我正在尝试使用其他三个列表(高,中和低)创建一个包含值的列表。新列表应该从probability_array中评估它应该从哪个列表中选择一个随机值。新列表应该是播放列表:在随机选择的值将被选取两次(从高,中或低)之前,特定列表(高,中或低)的所有其他值必须在新生成的列表中。< / p>

任何想法,我怎么能做到这一点。到目前为止我的代码:

import numpy as np


array_length = 30

high = [(1, 2), 3, 4, 5, 6, (7, 8, 9)]
medium = [10, 11, (12, 13), 14]
low = [100, 101, 102, (103, 104)]

probability_array = np.random.choice(
    ['High', 'Medium', 'Low',],
    array_length,
    p=[4/7, 2/7, 1/7]
)
# i. e.
"""
['Low' 'High' 'High' 'High' 'High' 'High' 'Medium' 'Medium' 'High' 'Medium'
 'High' 'High' 'Medium' 'Medium' 'High' 'High' 'Medium' 'Medium' 'High'
 'High' 'High' 'High' 'High' 'Medium' 'Medium' 'High' 'High' 'High' 'Low'
 'High']
"""

# new list should look like:
"""
[102, (1, 2), 4, (7, 8, 9), 3, 6, 14, ...]
"""

由于

3 个答案:

答案 0 :(得分:1)

带有np.random.choice

可以选择指定项目被选中的概率。您可以使用该列表构建high, medium, low的列表,并将其提供给另一个循环以正确构建播放列表 - 在roganjosh的建议中,我也删除了同一项目背靠背发生的能力

import numpy as np
import random 
import collections 

playlist_length = 30

# key is the match strength (ie. high, medium, low)
matches = {
    'high' : {
        'items' : [(1, 2), 3, 4, 5, 6, (7, 8, 9)],
        'prob' : 4/7
    },
    'medium' : {
        'items' : [10, 11, (12, 13), 14],
        'prob' : 2/7
    },
    'low' : {
        'items' : [100, 101, 102, (103, 104)],
        'prob' : 1/7
    }
}

# create two lists:
# a is a list of match strengths 
# p is the desired probability of an item from that match strength occuring
a, p = zip(*[(match, matches[match]['prob']) for match in matches])

# build a list of match strengths, with our chosen size and probability
results = np.random.choice(a=a, p=p, size=playlist_length)

# build our playlist 
playlist = []
last_item = None
for match_strength in results:
    # count all the items currently in playlist (a bit inefficient, probably don't have to recreate the Counter obj everytime)
    count_playlist = collections.Counter(playlist)

    # filter items of the given match strength, leaving out those that are at the current max 
    items = matches[match_strength]['items']
    max_count = max([count_playlist[item] for item in items])
    filtered = list(filter(lambda item: count_playlist[item] < max_count, items))

    # if all items have the same count, reset the filtered list to be any item
    if not len(filtered):
        filtered = items

    # drop last item so that it does not repeat
    if last_item and last_item in filtered and len(filtered) > 1:
        filtered.remove(last_item)

    # add one from filtered items to playlist
    new_item = random.choice(filtered)
    playlist.append(new_item)
    last_item = new_item

print(collections.Counter(results))
print(playlist)

输出:

计数器显示不同的匹配强度出现在可接受的频率Counter({'high': 19, 'medium': 10, 'low': 1})

并且播放列表是
[(1, 2), 14, 4, 5, 102, 3, (7, 8, 9), 6, (1, 2), 11, 10, (12, 13), 4, 3, 10, (12, 13), 5, 11, (7, 8, 9), 14, 6, 4, (7, 8, 9), 5, 10, (1, 2), 6, 3, 11, 4]

答案 1 :(得分:0)

我没有声明这种方法的效率(它说明了一种可能的方法,而不是最终的代码),但它可以确保每个列表(highmedium,{{1}在它重复第二次之前完全消耗等。它将适用于任何长度的最终序列,但它很容易导致相同的“轨道”背靠背出现。评论中没有澄清这是否是一个问题。

low

答案 2 :(得分:0)

试试这个:

def make_list(high, medium, low, parr):        
    _, (nhigh, nlow, nmed) = np.unique(parr, return_counts=True)
    # A check can be added to make sure labels are in the set ['High', 'Low', 'Medium']
    dl = {}
    dl['High'] = (nhigh // len(high) + 1) * np.random.permutation(np.asanyarray(high, dtype=np.object)).tolist()
    dl['Medium'] = (nmed // len(medium) + 1) * np.random.permutation(np.asanyarray(medium, dtype=np.object)).tolist()
    dl['Low'] = (nlow // len(low) + 1) * np.random.permutation(np.asanyarray(low, dtype=np.object)).tolist()
    play_list = []
    for p in parr:
        play_list.append(dl[p].pop())
    return play_list