【问题标题】:Randomly select values from list but with character length restriction从列表中随机选择值但有字符长度限制
【发布时间】:2018-11-25 19:59:45
【问题描述】:

我有两个字符串列表,如下所示:

test1 = ["abc", "abcdef", "abcedfhi"]

test2 = ["The", "silver", "proposes", "the", "blushing", "number", "burst", "explores", "the", "fast", "iron", "impossible"]

第二个列表较长,所以我想通过随机采样将其下采样到第一个列表的长度。

def downsample(data):
    min_len = min(len(x) for x in data)
    return [random.sample(x, min_len) for x in data]

downsample([list1, list2])

但是,我想添加一个限制,即从第二个列表中选择的单词必须与第一个列表的长度分布相匹配。所以对于随机选择的第一个词,它必须与较短列表的第一个词具有相同的长度。这里的问题是也不允许替换。

如何从test2 中随机选择与test1 的字符长度分布相匹配的n 个(较短列表的长度)元素? 谢谢, 杰克

【问题讨论】:

  • 我会将您的第二个列表变成一个字典,其中键是字符串长度,这样您就可以根据第一个列表中字符串的长度从该列表中随机抽样,这是一个 O( 1) 查找
  • @user3483203 很抱歉,我不确定我是否关注。如果您能将其写为答案,我将不胜感激,如果可行,我一定会接受。
  • 你能澄清你不想更换的意思吗?结果中的初始列表中是否没有任何个单词,或者它是基于索引的索引?
  • @user3483203 不想替换,我的意思是,如果test1 = ["abc", "abcdef","abcdef", "abcedfhi"],那么在下采样的第二个列表中,例如,银不能重复两次,因为它只在test2 中出现一次.
  • 感谢您的澄清,我会更新我的答案

标签: python


【解决方案1】:

设置

from collections import defaultdict
import random
dct = defaultdict(list)
l1 = ["abc", "abcdef", "abcedfhi"]
l2 = ["The", "silver", "proposes", "the", "blushing", "number", "burst", "explores", "the", "fast", "iron", "impossible"]

首先,使用collections.defaultdict创建一个字典,其中key是字长:

for word in l2:
  dct[len(word)].append(word)

# Result
defaultdict(<class 'list'>, {3: ['The', 'the', 'the'], 6: ['silver', 'number'], 8: ['proposes', 'blushing', 'explores'], 5: ['burst'], 4: ['fast', 'iron'], 10: ['impossible']})

然后您可以使用简单的列表推导以及 random.choice 来选择与您的第一个列表中每个元素的长度匹配的随机单词。如果您的字典中找不到字长,请填写-1

final = [random.choice(dct.get(len(w), [-1])) for w in l1]

# Output
['The', 'silver', 'blushing']

根据明确的要求进行编辑
如果列表 2 中不存在重复项,这是一种满足不允许重复项要求的方法:

for word in l2:
    dct[len(word)].append(word)

for k in dct:
    random.shuffle(dct[k])

final = [dct[len(w)].pop() for w in l1]
# ['The', 'silver', 'proposes']

如果第二个列表中没有足够的单词来完成分发,这种方法将引发 IndexError

【讨论】:

    【解决方案2】:

    一种方法可能是在test1 中创建项目长度的list。然后,用它来创建其他包含 这些长度的子列表来自test2。最后从列表列表中随机弹出(在similar answer 之后),以便在选择样本后删除该项目。

    from random import randrange
    
    test1 = ["abc", "abcdef", "abcedfhi"]
    test2 = ["The", "silver", "proposes", "the", "blushing", "number", "burst", "explores", "the", "fast", "iron", "impossible"]
    
    sizes = [len(i) for i in test1]
    # results: [3, 6, 8]
    
    sublists = [[item for item in test2 if len(item) == i] for i in sizes ]
    # results for sublists: [['The', 'the', 'the'], ['silver', 'number'], ['proposes', 'blushing', 'explores']]
    
    # randomly pop from the list for samples 
    samples = [i.pop(randrange(len(i)))  for i in sublists]
    
    print('Samples: ',samples)
    

    结果:

    Samples:  ['the', 'number', 'blushing']
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-11-12
      • 1970-01-01
      • 1970-01-01
      • 2011-07-19
      • 1970-01-01
      • 2021-03-22
      • 1970-01-01
      • 2017-07-30
      相关资源
      最近更新 更多