提问人:danny 提问时间:10/15/2023 最后编辑:danny 更新时间:10/15/2023 访问量:147
如何获取列表中某个数字的出现次数,并创建一个包含出现次数和后面的原始编号的新列表?
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?
问:
我得到了一个列表,可以放入一个函数中。然后假设该函数返回每个数字在函数中的次数。例如,如果给定的列表是 [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
这是我到目前为止所做的,但列表中的数字没有附加到它们的出现量。
答:
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]
你可以使用 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]
这个问题太模糊了。相同的数字总是彼此相邻还是可以传播?即:是总是还是可以?[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_NUMBER
MAX_NUMBER
我知道这些解决方案不是最短的,但它们比发布的解决方案更容易理解且更有效,因为它们不会对数据进行多次传递(尽管我怀疑 itertools 解决方案可能更快,因为它使用 C++,但从算法上讲,它仍然较慢,因为它进行一次分组,然后进行一些不必要的转换以获得组的长度。您始终可以通过在Cython之类的东西中编写自己的C++扩展来实现相同的性能。
没有必要把事情弄得太复杂,你可以用一个来实现你的目标。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。
- 否则,它会将以前的值添加到列表中并开始新的计数。
- 将最后一个值添加到列表中并返回它。
此外,在代码中,您使用了: .list = []
通常,在语言中的保留字之后命名变量是一种不好的做法,例如 .list
使用 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]
您还可以使用递归:
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
评论
[15,1,15]