1:3,6,8:10,16
Pythonのようなものに興味がある場合は、インデックス範囲の標準的な表記法と同様に、より良い選択だと思いますx:y
。構文により、オブジェクトでこの表記法を使用できます。呼び出しに注意してください
z[1:3,6,8:10,16]
に翻訳されます
z.__getitem__((slice(1, 3, None), 6, slice(8, 10, None), 16))
これは組み込みのコンテナであるTypeError
場合でもz
、NumPyの配列など、妥当なものを返すクラスを自由に作成できます。
5:
また、慣例により、無限のインデックス範囲を表すと言うこともでき:5
ます(Pythonには、負または無限に大きい正のインデックスを持つ組み込み型がないため、これは少し拡張されています)。
slice(16, None, None)
そして、これがパーサーです(以下で説明するグリッチに悩まされている美しいワンライナー):
def parse(s):
return [slice(*map(int, x.split(':'))) for x in s.split(',')]
ただし、落とし穴が1つあります。8:10
定義上、インデックス8と9のみが含まれ、上限はありません。それがあなたの目的に受け入れられないのであれば、あなたは確かに別のフォーマットが必要であり、1-3,6,8-10,16
私には似合います。その場合、パーサーは次のようになります。
def myslice(start, stop=None, step=None):
return slice(start, (stop if stop is not None else start) + 1, step)
def parse(s):
return [myslice(*map(int, x.split('-'))) for x in s.split(',')]
更新:結合された形式の完全なパーサーは次のとおりです。
from sys import maxsize as INF
def indices(s: 'string with indices list') -> 'indices generator':
for x in s.split(','):
splitter = ':' if (':' in x) or (x[0] == '-') else '-'
ix = x.split(splitter)
start = int(ix[0]) if ix[0] is not '' else -INF
if len(ix) == 1:
stop = start + 1
else:
stop = int(ix[1]) if ix[1] is not '' else INF
step = int(ix[2]) if len(ix) > 2 else 1
for y in range(start, stop + (splitter == '-'), step):
yield y
これは負の数も処理するので、
print(list(indices('-5, 1:3, 6, 8:15:2, 20-25, 18')))
プリント
[-5, 1, 2, 6, 7, 8, 10, 12, 14, 20, 21, 22, 23, 24, 25, 18, 19]
さらに別の方法は、使用すること...
です(Pythonは組み込みの定数省略記号として認識されるため、必要に応じて呼び出すことができます)が、読みにくいz[...]
と思います。1,...,3,6, 8,...,10,16