2014-02-03 4 views
3

Просматривая модуль itertools, я не вижу ничего, что можно было бы использовать в качестве общей, итерационной версии str.split. Есть ли простой, идиоматический способ сделать это?Аналог str.split для итераций?

Эти модульные тесты должны продемонстрировать, что я имею в виду:

class SplitAnalog(unittest.TestCase): 
    def test_splitEmpty(self): 
     """ 
     >>> ''.split() 
     [] 
     """ 
     actual = split(None, []) 
     self.assertEqual(tuple(actual),()) 

    def test_singleLine(self): 
     """ 
     >>> '123\n'.split() 
     ['123'] 
     """ 
     actual = split(lambda n: n is None, [1, 2, 3, None]) 
     self.assertEqual(tuple(tuple(line) for line in actual), ((1, 2, 3),)) 

    def test_allNones(self): 
     """ 
     >>> '\n\n\n'.split() 
     [] 
     """ 
     actual = split(lambda n: n is None, [None] * 3) 
     self.assertEqual(tuple(actual),()) 

    def test_splitNumsOnNone(self): 
     """ 
     >>> '314159\n26535\n89793'.split() 
     ['314159', '26535', '89793'] 
     """ 
     nums = [3, 1, 4, 1, 5, 9, None, 2, 6, 5, 3, 5, None, 8, 9, 7, 9, 3] 
     actual = split(lambda n: n is None, nums) 
     self.assertEqual(tuple(tuple(line) for line in actual), (
      (3, 1, 4, 1, 5, 9), 
      (2, 6, 5, 3, 5), 
      (8, 9, 7, 9, 3))) 

    def test_splitNumsOnNine(self): 
     nums = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 9, 8, 7, 3] 
     actual = split(lambda n: n == 9, nums) 
     self.assertEqual(tuple(tuple(line) for line in actual), (
      (3, 1, 4, 1, 5,), 
      (2, 6, 5, 3, 5), 
      (8, 7, 3))) 

Что бы такая функция называться? Я не могу найти пример, даже когда я ткнул в other language libraries.

ответ

1

Предполагая, что я понимаю, что вы после этого, может быть,

def pseudosplit(predicate, seq): 
    return (tuple(g) for k,g in groupby(seq, key=lambda x: not predicate(x)) if k) 

, который производит

>>> list(pseudosplit(lambda x: x is None,())) 
[] 
>>> list(pseudosplit(lambda x: x is None, [1,2,3])) 
[(1, 2, 3)] 
>>> list(pseudosplit(lambda x: x is None, [None]*3)) 
[] 
>>> list(pseudosplit(lambda x: x is None, [3, 1, 4, 1, 5, 9, None, 2, 6, 5, 3, 5, None, 8, 9, 7, 9, 3, None])) 
[(3, 1, 4, 1, 5, 9), (2, 6, 5, 3, 5), (8, 9, 7, 9, 3)] 

, который, кажется, чтобы разделить, как это делают ваши тестовые случаи, в любом случае.

+0

Мне нравится! Он проходит тесты. –

+0

@MichaelKropat: ваше редактирование моего кода сломало все примеры. – DSM

+0

oops :(Я могу исправить это –

0

Вот пример реализации:

def split(predicate, iterable): 
    iterable = iter(iterable) 
    line = [] 
    try: 
     while True: 
      val = next(iterable) 
      if predicate(val): 
       if line: 
        yield line 
       line = [] 
      else: 
       line.append(val) 
    except StopIteration: 
     if line: 
      yield line 

Интересно, хотя, если я с видом на более простой, более легкий, более-идиоматических путь. Кто угодно?

1

Это будет разделено на основе предиката.

def split(predicate, iterable): 
    groups = (tuple(g) for k, g in groupby(iterable, predicate)) 
    return (g for g in groups if not all(imap(predicate, g))) 

Проходит все испытания, включая тест с чем-то иным, чем Нет.

def test_splitNumsOnNine(self): 
    """ 
    >>> '314159265359873\n'.split() 
    ['31415', '26535', '873'] 
    """ 
    nums = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 9, 8, 7, 3] 
    actual = split(lambda n: n is 9, nums) 
    self.assertEqual(tuple(tuple(line) for line in actual), (
     (3, 1, 4, 1, 5,), 
     (2, 6, 5, 3, 5), 
     (8, 7, 3))) 
+0

Плакат и увидел, что ответы DSM лучше. – Rod

Смежные вопросы