首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >将整数列表映射到python中的相应范围。

将整数列表映射到python中的相应范围。
EN

Stack Overflow用户
提问于 2017-09-08 09:08:09
回答 4查看 655关注 0票数 0

我想合并一个列表到范围,但保持原来的顺序。同时有定制的间隙支持。

例如,当输入列表[0, 1, 3, 7, 4, 2, 8, 9, 11, 11]时,预期它将返回一个范围列表["0-4", "0-4", "7-9", "0-4", "0-4", "0-4", "7-9", "7-9", "11-11", "11-11"]

代码语言:javascript
运行
复制
def fun(a_list, gap_length=0):
    return a_list_of_range

# from
# [0, 1, 3, 7, 4, 2, 8, 9, 11, 11]
# to
# ["0-4", "0-4", "7-9", "0-4", "0-4", "0-4", "7-9", "7-9", "11-11", "11-11"]
# or to
# {0:"0-4", 1:"0-4", 2:"0-4", 3:"0-4", 4:"0-4", 7:"7-9", 8:"7-9", 9:"7-9", 10:"11-11"}

堆栈溢出上有一个similar question,但是所有的答案都不能按照相应的顺序返回范围。

你的解决方案是什么?

我写了一个很难看的函数来解决这个问题,但是速度太快了。下面的函数支持自定义间隙长度,以便将列表合并到范围中。

代码语言:javascript
运行
复制
def to_ranges_with_gap(input_list, gap_len=20):
    """list into range with gap"""
    loc2range = {}
    input_list = sorted(set(input_list))
    start_loc = input_list[0]
    stop_loc = input_list[0]
    range_loc_list = []
    for element in input_list:
        if element < stop_loc + gap_len:
            range_loc_list.append(element)
            stop_loc = element
        else:

            for loc in range_loc_list:
                loc2range[loc] = "{}-{}".format(start_loc, stop_loc)

            start_loc = element
            stop_loc = element
            range_loc_list = [element]

        for loc in range_loc_list:
            loc2range[loc] = "{}-{}".format(start_loc, stop_loc)

    return loc2range

你能告诉我一种更好的方法吗?

名单是什么样子的?

清单如下:

  • 重复
  • 未排序
  • 不连续
  • 大量的元素。数以十亿计的数字从0到10^10,因此速度很重要。

在结果列表中重复范围的目的是什么?您也许可以编写一个更优雅的解决方案,而不需要这种怪癖。- timgeb

例如,如果我想处理下面的数据,并尝试分组年龄范围来计算中间高度。

代码语言:javascript
运行
复制
Age  Gender  Height 
2    M       30
4    M       60
2    M       33
3    F       50
20   M       180
22   F       166
40   F       150
33   M       172
...

我希望能得到这样的结果。和年龄列,上面提到的list

代码语言:javascript
运行
复制
2-5  M    40.5
2-6  F    50.9
10-25 M   150.8
...

因此,如果我可以直接合并dataframe,而不生成映射程序并再次将其映射到dataframe,则会更好。

EN

回答 4

Stack Overflow用户

发布于 2017-09-08 09:30:27

我已经修改了来自similar question的接受答案代码,您提供了这个代码,并且它对我有效。

代码语言:javascript
运行
复制
import itertools

def ranges(i):
    for a, b in itertools.groupby(enumerate(i), lambda i: i[1] - i[0]):
        b = list(b)
        if(b[0][1] - b[-1][1] == 0):
                yield "%d-%d"%(b[0][1], b[-1][1])
        for ele in range(b[0][1], b[-1][1]):
                yield "%d-%d"%(b[0][1], b[-1][1])

print ([ele for ele in ranges([0, 1, 2, 3, 4, 7, 8, 9, 11])])

“0-4”、“0-4”、“0-4”、“0-4”、“7-9”、“7-9”、“11-11”

注:请告诉我,如果这是错误的方式回答,将处理它从下一次。我的意图只是给出适当的答案,帮助别人,而不是接受别人的回答等等。

请评论下面,如果是这样,将删除我的答案。

我知道,这是个坏兆头。

票数 1
EN

Stack Overflow用户

发布于 2017-09-08 09:56:15

这将返回您似乎正在寻找的结果。它并不比你所拥有的更漂亮,但它有效:

代码语言:javascript
运行
复制
#!/usr/bin/python

arr = []
l = [1,2,3,5,6,7,8,9,11,12,13,14,20]
start,counter,i = (0,0,0)

while i < len(l):
    start = i
    counter = 0
    while (i < len(l) - 1) and (l[i+1] == l[i] +1):
        counter += 1
        i += 1
    for x in range(counter+1):
        arr.append("{}-{}".format(l[start], l[start+counter]))
    i += 1

print(arr)

产出:

代码语言:javascript
运行
复制
['1-3', '1-3', '1-3', '5-9', '5-9', '5-9', '5-9', '5-9', '11-14', '11-14', '11-14', '11-14', '20-20']
票数 0
EN

Stack Overflow用户

发布于 2017-09-08 10:02:02

代码语言:javascript
运行
复制
import itertools as it
import collections as ct


# Given
a = [0, 1, 2, 3, 4, 7, 8, 9, 11]
b = [0, 1, 3, 7, 4, 2, 8, 9, 11]                       # unsorted
c = [0, 15, 2, 3, 4, 7, 8, 9, 11, 14]                  # unsorted
d = [0, 15, 2, 3, 4, 7, 8, 9, 11, 14, 2, 4]            # duplicates 


def find_ranges(iterable):
    """Return a defaultdict of ranges."""
    # Find ranges
    sorted_it = sorted(set(iterable))
    keyfunc = lambda i:  sorted_it[i[0]] - i[0]
    ranges = [[item[1] for item in g] 
            for k, g in it.groupby(enumerate(sorted_it), keyfunc)]
    # Out: [[0, 1, 2, 3, 4], [7, 8, 9], [11]]

    # Build dictionary
    dd = ct.defaultdict(int)
    for r in ranges:
        s = "{}-{}".format(min(r), max(r))
        for i in r:
            if i in r:
                dd[i] = s
    return dd

find_ranges(a)

输出

代码语言:javascript
运行
复制
defaultdict(int,
            {0: '0-4',
            1: '0-4',
            2: '0-4',
            3: '0-4',
            4: '0-4',
            7: '7-9',
            8: '7-9',
            9: '7-9',
            11: '11-11'})

一旦有了这个查找表,创建一个范围列表就很简单了:

代码语言:javascript
运行
复制
[find_ranges(b)[i] for i in b]
# ['0-4', '0-4', '0-4', '7-9', '0-4', '0-4', '7-9', '7-9', '11-11']

详细信息

此外,该函数为未排序的迭代(bc)查找范围,并处理重复项(d)。

代码语言:javascript
运行
复制
assert find_ranges(a) == find_ranges(b)
assert find_ranges(c) == find_ranges(d)

在这里,我们将确认结果是等价的排序和未排序的输入。接下来,我们将确认未排序输入和带有重复元素的输入的等价性。最后,我们演示了一个示例输出:

代码语言:javascript
运行
复制
find_ranges(d)

输出

代码语言:javascript
运行
复制
defaultdict(int,
        {0: '0-0',
         2: '2-4',
         3: '2-4',
         4: '2-4',
         7: '7-9',
         8: '7-9',
         9: '7-9',
         11: '11-11',
         14: '14-15',
         15: '14-15'})

注:“查找范围”部分的灵感来源于@Nirmi的帖子,这是一个伟大的贡献。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46112731

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档