我不太清楚如何提出这个问题,甚至在Google上搜索答案,但我会在这里写出来。我有一个整数的排序列表,对应于文件中的行号。我想将它们转换为字符串,但对于顺序的数字,我希望字符串具有序列的第一个数字,短划线,然后是最后一个数字。这是一个例子:
line_nums = [ 1, 2, 3, 5, 7, 8, 9, 10 ]
我想将该列表转换为:
[ '1-3', '5', '7', '8-10' ]
我写了一些大部分都有效的代码。在某些序列中,它会将相同的数字放在字符串中两次。在最近执行此代码时,输入是:
[ 10007, 10008, 10009, 10010, 10011, 10013, 10015, 10016, 10017, 10018, 10019 ]
但我得到的是:
[ '10007-10011', '10013-10013', '10015-10019' ]
这是我的代码:
def get_line_numbers_concat(line_nums):
seq = []
final = []
last = 0
for index, val in enumerate(line_nums):
if last + 1 == val or index == 0:
seq.append(val)
last = val
else:
final.append(str(seq[0]) + '-' + str(seq[len(seq)-1]))
seq = []
seq.append(val)
last = val
if index == len(line_nums) - 1:
if len(seq) > 1:
final.append(str(seq[0]) + '-' + str(seq[len(seq)-1]))
else:
final.append(str(seq[0]))
final_str = ', '.join(map(str, final))
return final_str
答案 0 :(得分:5)
除了seq[0]
实际上与seq[len(seq)-1]
相同的元素,然后您将其简化为len(seq)==1
的情况或如下所示{{1}然后你执行正常处理,否则只需添加第一个元素。
if len(seq) > 1
答案 1 :(得分:2)
您可能可能会重新安排代码,以便在最后一个案例中不必复制,但是可以使用其中的内容:
查看第一个if..else,
对于单值序列, str(seq[len(seq)-1]))
将等于str(seq[-1])
,这与str(seq[0])
相同。我认为这会给你"10013-10013"
。
尝试在{1}}之上添加一个if len(seq) > 1:
,看看这在抑制它方面是否有用。你可能还需要一个类似的if / else来处理一个数字的情况。
答案 2 :(得分:2)
您可以使用OrderedDict使用新序列的开头作为键,并在最后一个等于当前+ 1时附加值,然后加入子列表的第一个和最后一个元素(如果多于一个)元素或者只是添加单个元素:
from collections import OrderedDict
od = OrderedDict()
# create iterator
it = iter(l)
# get first element to use as starting key
key = next(it)
od[key] = [key]
# keep track of previous element
prev = key
for i in it:
# if last element + 1 is equal to the current
# add it to the current sequence
if prev + 1 == i:
od[key].append(i)
else:
# else start a new sequence adding key
key = i
od[key] = [i]
# update prev
prev = i
# if a sublist had len > 1 we have a sequence so join first and last
# elements using str.format or else we just extract a single element
print(["{}-{}".format(sub[0], sub[-1]) if len(sub) > 1 else str(sub[0]) for sub in od.values()])
['10007-10011', 10013, '10015-10019']
您可以使用key = l[0]
然后for i in l[1:]
但切片会创建一个新列表,因此使用iter
可以让我们使用next
获取第一个元素,将指针移动到第二个元素元素,它允许我们提取第一个元素,只是迭代其余元素而不切片。
In [7]: l = [1,2,3,4]
In [8]: it = iter(l)
In [9]: next(it) # first element
Out[9]: 1
In [10]: next(it) # second element ...
Out[10]: 2
In [11]: next(it)
Out[11]: 3
In [12]: next(it)
Out[12]: 4
当你遍历iter
对象时,它与调用next
相同,所以当我们用next
删除第一个元素时,我们会迭代余数。
In [13]: l = [1,2,3,4]
In [14]: it = iter(l)
In [15]: key = next(it)
In [16]: key
Out[16]: 1
In [17]: for i in it:
....: print(i)
....:
2
3
4
您也可以在没有dict的情况下执行此操作,如果序列中至少有两个,则将标志设置为True:
key, out = next(it), []
prev, flag = key, False
for i in it:
if prev + 1 == i:
flag = True
else:
# if flag is set we have a sequence else just add the key
out.append("{}-{}".format(key, prev) if flag else str(key))
# reset flag
flag = False
key = i
prev = i
# catch last element
out.append("{}-{}".format(key, prev) if flag else str(key))
答案 3 :(得分:0)
我想提供一种替代解决方案,对我来说,看起来更简单 并且更容易使用。
这是因为它看起来完全像一个可以很容易解决的问题
左侧折叠,这正是reduce
在python中的内容
(http://en.wikipedia.org/wiki/Fold_%28higher-order_function%29)
reduce(function,iterable [,initializer])
将两个参数的函数累加到可迭代的项目中,从左到右,以便将迭代减少到单个值。例如,reduce(lambda x,y:x + y,[1,2,3,4,5])计算(((((1 + 2)+3)+4)+5)。左参数x是累加值,右参数y是迭代的更新值。如果存在可选的初始值设定项,则它将放置在计算中的iterable项之前,并在iterable为空时用作默认值。如果未给出初始化程序且iterable只包含一个项目,则返回第一个项目。大致相当于:
简单地说,我会处理iterable
,这将是line_nums
使用提供的function
一次一个值,由{I}决定
如果该值是已创建序列的一部分。这样我就会结束
用表示连续数字序列的列表列表。然后我
将它们转换为范围(xx-yy
)或仅转换为单个值(xx
)字符串。
所以我的解决方案看起来像这样:
def make_sequences(sequences, val):
if sequences != [] and sequences[-1][-1] == val - 1:
return sequences[:-1] + [sequences[-1] + [val]]
return sequences + [[val]]
def sequence_to_string(s):
return '%s-%s' % (s[0], s[-1]) if len(s) > 1 else str(s[0])
def get_line_numbers_concat(line_nums):
return ', '.join(
sequence_to_string(seq)
'%s-%s' % (seq[0], seq[-1])
for seq in reduce(make_sequences, line_nums, [])
)
sequence_to_string(..)
和get_line_numbers_concat(..)
函数是
非常简单,所以我只是解释一下里面发生了什么
make_sequences(..)
:
def make_sequences(sequences, val):
在第一次通话时,他sequences
将为[]
(因为这已传递给reduce
在get_line_numbers_concat(..)
),在后续的电话中,这就是
结果列表将构建 - 结果
make_sequences(..)
将sequences
传递给make_sequences(..)
后续调用
line_nums
。为了说清楚,这是如何使用它来调用它
原make_sequences([], 10007)
==> [[10007]]
make_sequences([[10007]], 10008)
==> [[10007, 10008]]
...
make_sequences([[10007, 10008, 10009, 10010, 10011]], 10013)
==> [[10007, 10008, 10009, 10010, 1011], [10013]]
...
:
val
然后我们只需决定sequences
是否属于最后一个序列
if sequences != [] and sequences[-1][-1] == val - 1: # (1)
:
sequences
这可以确保sequences[-1][-1]
不为空(否则我们会得到
索引错误),然后我们检查最后一个序列中的最后一个数字
序列(即val - 1
等于val
因此
return sequences[:-1] + [sequences[-1] + [val]]
应附加到最后一个序列。
这是在这里完成的:
sequences[:-1]
我们获取除最后一个序列(val
)之外的所有序列并追加
给他们一个新的序列,这是将(1)
追加到最后的结果
序列
但是如果条件seqences == []
不成立 - 这意味着要么没有
先前的序列(val
)或最后一个序列的最后一个数字
并不比val
少一个。在那种情况下,我们添加一个新序列
只有一个值 return sequences + [[val]]
:
{{1}}
答案 4 :(得分:0)
我尽量避免:
这是我的解决方案:
{
#include<stdio.h>
#include<stdint.h>
#include<sys/ipc.h>
#include<sys/shm.h>
int main(int argc, char *argv[])
{
int ret = 0;
int shmid = 0;
int key = 0xbade;
struct shmid_ds shmi = {0};
shmid = shmget(key, 0x200000, IPC_CREAT|0666);
if (shmid < 0)
perror("shmget");
ret = shmctl(shmid, IPC_STAT, (struct shmid_ds *)&shmi);
if (ret < 0)
perror("shmctl");
shmi.shm_perm.uid = 0;
shmi.shm_perm.cuid = 0;
shmi.shm_perm.cgid = 0;
shmi.shm_perm.gid = 0;
ret = shmctl(shmid, IPC_SET, (struct shmid_ds *)&shmi);
if (ret < 0)
perror("shmctl");
return 0;
}
}