簡體   English   中英

如何使用另一個列表作為參考替換列表中的連續值?

[英]How to replace consecutive values in a list using another list as a reference?

我有一個這樣的列表:

list_target = [4, 5, 6, 7, 12, 13, 14]
list_primer = [3, 11]

所以list_target由連續值塊組成,它們之間是值的跳轉(如從712 )。 list_primer由這些塊開頭的值組成。 list_primer中的元素是在另一個進程中生成的。

我的問題是:對於list_primer的每個元素,如何識別list_target中的塊並用我想要的替換它們的值? 例如,如果我選擇將第一個塊中的值替換為1 ,將第二個塊中的值替換為0 ,則結果如下所示:

list_target_result = [1, 1, 1, 1, 0, 0, 0]

這是一個簡單的算法,它通過從頭到尾遍歷兩個列表來解決您的任務:

list_target = [4, 5, 6, 7, 12, 13, 14]
list_primer = [3, 11]

block_values = [1, 0]

result = []

for i, primer in enumerate(list_primer):
    for j, target in enumerate(list_target):
        if target == primer+1:
            primer += 1
            result.append(block_values[i])
        else:
            continue
print(result)
[1, 1, 1, 1, 0, 0, 0]

請注意,如果並非所有塊都有各自的引物,您可能會遇到麻煩,具體取決於您的用例。

修改方法以在列表中查找嚴格遞增的數字組

def group_seq(l, list_primer): 
    " Find groups which are strictly increasing or equals next list_primer value "
    temp_list = cycle(l)
    temp_primer = cycle(list_primer)

    next(temp_list) 
    groups = groupby(l, key = lambda j: (j + 1 == next(temp_list)) or (j == next(temp_primer))) 
    for k, v in groups: 
        if k: 
            yield tuple(v) + (next((next(groups)[1])), )

使用 group_seq 在 list_target 中查找嚴格遞增的塊

list_target = [4, 5, 6, 7, 12, 13, 14]
list_primer = [3, 11]
block_values = [1, 0]

result = []
for k, v in zip(block_values, group_seq(list_target, list_primer)):
    result.extend([k]*len(v))  # k is value from block_values
                               # v is a block of strictly increasing numbers
                               # ie. group_seq(list_target) creates sublists
                               # [(4, 5, 6, 7), (12, 13, 14)]

print(result)
Out: [1, 1, 1, 1, 0, 0, 0]

這是一個適用於O(n)的解決方案,其中n=len(list_target) 它假定您的 list_target 列表按照您描述的方式是連續的(在塊內增量為 1,在塊之間增量大於 1)。

它返回一個字典,其中每個塊的開頭作為鍵(潛在引物),該塊在 list_target 中的上下索引作為值。 然后訪問該字典是O(1)

list_target = [4, 5, 6, 7, 12, 13, 14]
list_primer = [3, 11]

block_dict = dict()
lower_idx = 0
upper_idx = 0 

for i, val in enumerate(list_target):  # runs in O(n)
  upper_idx = i + 1
  if i == len(list_target) - 1:  # for last block in list
    block_dict[list_target[lower_idx] - 1] = (lower_idx, upper_idx)
    break
  if list_target[i + 1] - list_target[i] != 1:  #if increment more than one, save current block to dict, reset lower index
    block_dict[list_target[lower_idx] - 1] = (lower_idx, upper_idx)
    lower_idx = i + 1

結果如下:

print(block_dict)  # quick checks
>>>> {3: (0,4), 11: (4,7)}

for p in list_primer:  # printing the corresponding blocks.
    lower, upper = block_dict[p]  # dict access in O(1)
    print(list_target[lower:upper])
>>>> [4, 5, 6, 7]
     [12, 13, 14]

# getting the indices for first primer marked as in your original question:
list_target_result = [0] * len(list_target)
lower_ex, upper_ex = block_dict[3]
list_target_result[lower_ex: upper_ex] = [1]*(upper_ex-lower_ex)
print(list_target_result)
>>>> [1, 1, 1, 1, 0, 0, 0]

這是使用numpy的解決方案。

import numpy as np

list_target = np.array([4, 5, 6, 7, 12, 13, 14])
list_primer = np.array([3, 11])

values = [1, 0]

ix  = np.searchsorted(list_target, list_primer)
# [0,4]

blocks = np.split(list_target, ix)[1:]
# [array([4, 5, 6, 7]), array([12, 13, 14])]

res = np.concatenate([np.full(s.size, values[i]) for i,s in enumerate(blocks)])
# array([1, 1, 1, 1, 0, 0, 0])

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM