Slicy 每第 n 个元素,而不是从第一个元素开始
Slicy every nth element, not beginnint with the first
如何优雅地将一个 python 列表分成两部分,以便第二个包含第一个列表的第 n 个元素,并将这些切片元素从第一个列表中删除? 切片不应该从第一个元素开始!
示例:
split_data([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15])
应该return
([1,2,3,4,6,7,8,9,11,12,13,14], [5,10,15])
谢谢:)
编辑:
对于选择第 n 个元素的部分,我尝试了以下操作:
test = data[::5]
train = data
del data[::5]
return (train, test)
然而,对于 split_data(list(range(1, 30)))
,这只会 return ([2, 3, 4, 5, 7, 8, 9, 10, 12, ...], [1, 6, 11, 16, 21, 26])
。
使用 elegant 我想表达我想避免使用 for 循环遍历列表 ;)
您可以利用 list.pop()
按索引删除元素以及 returns 它。因此,您的原始列表将不包含这些数字,并且通过使用弹出的项目创建一个新列表,您可以获得第二个列表。
def split(l,n):
return (l, [l.pop(i) for i in range(n, len(l), n)])
>>>l = list(range(1,16))
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
>>>split(l,4)
([1, 2, 3, 4, 6, 7, 8, 9, 11, 12, 13, 14], [5, 10, 15])
这将改变作为参数传递的列表。如果您希望您的函数保持原样,只需在添加 l
之前添加 l=list(l)
。
感谢@abstractbyte,这个答案无效,因为list.pop()
在迭代时减少了列表的长度,最终导致索引超出范围。
然而,使用numpy
或pandas
仍然可以“优雅地”解决同样的问题:
- numpy:
def slice_numpy(l, n):
l = np.array(l)
mask = list(range(n-1,len(l),n))
return np.delete(l, mask), l[mask]
# note that `len` and `delete` will work as expected on 1D arrays. if you have a 2D dataset you need to modify them accordingly
- pandas
def slice_pandas(l, n):
l = pd.Series(l)
mask = list(range(n-1,len(l),n))
return l.drop(mask), l[mask]
- 示例:
>>> l = list(range(1, 16))
>>> l
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
>>>
>>>
>>> train, test = slice_numpy(l, 5)
>>> train
array([ 1, 2, 3, 4, 6, 7, 8, 9, 11, 12, 13, 14])
>>> test
array([ 5, 10, 15])
>>>
>>>
>>> train, test = slice_pandas(l, 5)
>>> train
0 1
1 2
2 3
3 4
5 6
6 7
7 8
8 9
10 11
11 12
12 13
13 14
dtype: int64
>>> test
4 5
9 10
14 15
dtype: int64
如何优雅地将一个 python 列表分成两部分,以便第二个包含第一个列表的第 n 个元素,并将这些切片元素从第一个列表中删除? 切片不应该从第一个元素开始!
示例:
split_data([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15])
应该return
([1,2,3,4,6,7,8,9,11,12,13,14], [5,10,15])
谢谢:)
编辑: 对于选择第 n 个元素的部分,我尝试了以下操作:
test = data[::5]
train = data
del data[::5]
return (train, test)
然而,对于 split_data(list(range(1, 30)))
,这只会 return ([2, 3, 4, 5, 7, 8, 9, 10, 12, ...], [1, 6, 11, 16, 21, 26])
。
使用 elegant 我想表达我想避免使用 for 循环遍历列表 ;)
您可以利用 list.pop()
按索引删除元素以及 returns 它。因此,您的原始列表将不包含这些数字,并且通过使用弹出的项目创建一个新列表,您可以获得第二个列表。
def split(l,n):
return (l, [l.pop(i) for i in range(n, len(l), n)])
>>>l = list(range(1,16))
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
>>>split(l,4)
([1, 2, 3, 4, 6, 7, 8, 9, 11, 12, 13, 14], [5, 10, 15])
这将改变作为参数传递的列表。如果您希望您的函数保持原样,只需在添加 l
之前添加 l=list(l)
。
感谢@abstractbyte,这个答案无效,因为list.pop()
在迭代时减少了列表的长度,最终导致索引超出范围。
然而,使用numpy
或pandas
仍然可以“优雅地”解决同样的问题:
- numpy:
def slice_numpy(l, n):
l = np.array(l)
mask = list(range(n-1,len(l),n))
return np.delete(l, mask), l[mask]
# note that `len` and `delete` will work as expected on 1D arrays. if you have a 2D dataset you need to modify them accordingly
- pandas
def slice_pandas(l, n):
l = pd.Series(l)
mask = list(range(n-1,len(l),n))
return l.drop(mask), l[mask]
- 示例:
>>> l = list(range(1, 16))
>>> l
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
>>>
>>>
>>> train, test = slice_numpy(l, 5)
>>> train
array([ 1, 2, 3, 4, 6, 7, 8, 9, 11, 12, 13, 14])
>>> test
array([ 5, 10, 15])
>>>
>>>
>>> train, test = slice_pandas(l, 5)
>>> train
0 1
1 2
2 3
3 4
5 6
6 7
7 8
8 9
10 11
11 12
12 13
13 14
dtype: int64
>>> test
4 5
9 10
14 15
dtype: int64