如何获取列表中某个数字的出现次数,并创建一个包含出现次数和后面的原始编号的新列表?

How to take the number of occurrences of a number in a list and create a new list that has the occurrence number and the original number after it?

提问人:danny 提问时间:10/15/2023 最后编辑:danny 更新时间:10/15/2023 访问量:147

问:

我得到了一个列表,可以放入一个函数中。然后假设该函数返回每个数字在函数中的次数。例如,如果给定的列表是 [15,15,15,6,6,6,7,7],则输出列表应该是 [3,15,3,6,2,7]。

def encode_rle(flat_data):
    set_list = set(flat_data)
    flat_data_converted = []
    for value in set_list:
        flat_data_converted.append(value)
    list = []
    for number in flat_data_converted:
        amount = flat_data.count(number)
        list.append(amount)

    new_list = flat_data_converted + list

这是我到目前为止所做的,但列表中的数字没有附加到它们的出现量。

Python list 函数

评论

2赞 Andrej Kesely 10/15/2023
的输出应该是什么?[15,1,15]
0赞 danny 10/15/2023
[1,15,1,1,1,15]
0赞 Marcin Orlowski 10/15/2023
函数名称中的 RLE 表明 OP 正在执行运行长度编码

答:

1赞 Marcin Orlowski 10/15/2023 #1
def encode_rle(flat_data):
    result = []
    i = 0
    n = len(flat_data)
    while i < n:
        count = 1
        while i + 1 < n and flat_data[i] == flat_data[i + 1]:
            count += 1
            i += 1
        result.extend([count, flat_data[i]])
        i += 1
    return result

flat_data = [15,15,15,6,6,6,7,7]
print(flat_data)
print(encode_rle(flat_data))

预期输出:[3, 15, 3, 6, 2, 7]

2赞 Andrej Kesely 10/15/2023 #2

你可以使用 itertools.groupby

from itertools import groupby

lst = [15, 15, 15, 6, 6, 6, 7, 7]

out = []
for value, group in groupby(lst):
    out.extend([sum(1 for _ in group), value])

print(out)

指纹:

[3, 15, 3, 6, 2, 7]
0赞 OM222O 10/15/2023 #3

这个问题太模糊了。相同的数字总是彼此相邻还是可以传播?即:是总是还是可以?[15,15,15,6,6,6,7,7][15,6,7,15,6,7,15,6]

如果它们总是紧挨着,你可以做:

lst = [15,15,15,6,6,6,7,7]

def convert(lst):
    output = []
    n = lst[0] # start with the first number
    count = 1
    for number in lst[1:]: # iterate through all other numbers
        if number == n: # if the new number is the same as the old one, increment the count
            count += 1
        else: #if you found a new number, add the current count and number to output and updated n
            output.append(count)
            output.append(n)
            n = number
            count = 1
    # at the end of the loop since all the numbers were the same, you still need to add the final result to the output
    output.append(count)
    output.append(number)
    return output

print(convert(lst))

如果没有,您需要使用字典来计算每个数字的出现次数:

lst = [15,6,7,15,6,7,15,6]

def convert(lst):
    occurances = {}
    for number in lst:
        if number in occurances: # if we have already encountered this number, incerement its count:
            occurances[number] += 1
        else: # if it's a new number, set its count to 1
            occurances[number] = 1
        # this can be simplified using python's default dict but I coded it like this so it's easy to understand
    output = []
    for number in occurances:
        output.append(occurances[number])
        output.append(number)
    return output

print(convert(lst))

如果遇到的数字有上限(例如,如果最大值为 1000 或更小),则可以使用每个数字的索引处的值来创建一个列表,然后增加该值。这通常是在处理 ASCII 字符时完成的,因为使用具有直接索引的数组(列表)比使用字典更快,但它不适用于较大的值,因为它使用大量内存。counts = [0]*MAX_NUMBERMAX_NUMBER

我知道这些解决方案不是最短的,但它们比发布的解决方案更容易理解且更有效,因为它们不会对数据进行多次传递(尽管我怀疑 itertools 解决方案可能更快,因为它使用 C++,但从算法上讲,它仍然较慢,因为它进行一次分组,然后进行一些不必要的转换以获得组的长度。您始终可以通过在Cython之类的东西中编写自己的C++扩展来实现相同的性能。

1赞 nokla 10/15/2023 #4

没有必要把事情弄得太复杂,你可以用一个来实现你的目标。for-loop

def encode_rle(flat_data):
    if not flat_data:
        return []

    new_lst = [1]
    for idx in range(1, len(flat_data)):
        if flat_data[idx] == flat_data[idx - 1]:
            new_lst[-1] += 1
        else:
            new_lst += flat_data[idx - 1], 1
    return new_lst + [flat_data[-1]]
        

print(encode_rle([15,15,15,6,6,6,7,7]))
print(encode_rle([15, 1, 15]))

输出:

[3, 15, 3, 6, 2, 7]
[1, 15, 1, 1, 1, 15]

上面的代码:

  1. 检查列表是否为空
  2. 在新列表的最后一个单元格处设置一个计数器,并向其添加一个计数器(列表的第一个元素)
  3. 循环浏览列表的其余部分:
    • 如果该值等于之前的值,则向计数器加 1。
    • 否则,它会将以前的值添加到列表中并开始新的计数。
  4. 将最后一个值添加到列表中并返回它。

此外,在代码中,您使用了: .list = []

通常,在语言中的保留字之后命名变量是一种不好的做法,例如 .list

0赞 rickhg12hs 10/15/2023 #5

使用 more-itertools 包,您可以轻松完成。

from more_itertools import run_length, flatten

def encode_rle(flat_data):
    return list(flatten([b,a] for a,b in run_length.encode(flat_data)))

例子:

print(encode_rle([15,15,15,6,6,6,7,7]))
[3, 15, 3, 6, 2, 7]

print(encode_rle([15,1,15]))
[1, 15, 1, 1, 1, 15]
0赞 algebruh 10/15/2023 #6

您还可以使用递归:

def encode_rle(flat_data):
    if len(flat_data) <= 1:
        return [1] * len(flat_data) + flat_data
    else:
        encoded_list = encode_rle(flat_data[1:])
        if flat_data[0] == encoded_list[1]:
            encoded_list[0]+=1
        else:
            encoded_list = [1, flat_data[0]] + encoded_list
        return encoded_list