2016-08-02 10 views
3

Учитывая 2D-список:выберите элементы в списке по появлению нулей в питона

X = [ [a,2], [b,12], [c,6], [d,0], [e,2], [f,0], [g,0], [h,12], [i,18] ] 

мне нужно получить 2D список, который группирует все подсписки, отделенные нулями в X[1] колонке. Я имею в виду, мне нужно выбрать:

Y = [ [[a,2],[b,12],[c,6]], [[e,2]], [[h,12],[i,18]] ] 

анг получить список соответствующих записей X[0] только:

Y = [ [a, b, c], [e], [h, i] ] 

Я уже задавал подобный вопрос для выбора элементов в списке, на основы появления нулей внутри него, но это был 1-й список. Используя itertools, я пытался что-то вроде:

Z = [list(v) for k, v in itertools.groupby(X[:,1], lambda x: x == 0) if not k] 

где я X[:,1] действовать на X[1] части списка, так как отбор действует на нее. Но это, очевидно, дает мне X[1] часть списка:

Z = [[2, 12, 6], [2], [12, 18]] 

Но мне нужно X[0] колонки ... как я могу использовать itertools на многомерных списков? Заранее спасибо.

+0

вопрос не совсем ясен. каков ваш вклад и каков ожидаемый результат?«разделены нулями»? Я не видел нулей в вашем примере. попытался понять в течение двух минут и не удалось – Elisha

+0

Вход в 'X', а желаемый результат -' Y' (второй). И нули находятся в 'X [1]' части списка 'X' (' [d, 0], [f, 0], [g, 0] '). – urgeo

ответ

2

Я считаю, что это будет делать работу:

[map(lambda a:a[0],list(v)) for k, v in itertools.groupby(X, lambda x: x[1] == 0) if not k] 

Больше объяснения:

вы хотите GroupBy X в соответствии со вторым значением каждого элемента в списке, так что вам нужно сделать:
itertools.groupby(X, lambda x: x[1] == 0)

[list(v) for k, v in itertools.groupby(X, lambda x: x[1] == 0) if not k] создаст список 2D вроде:
[[['a', 2], ['b', 12], ['c', 6]], [['e', 2]], [['h', 12], ['i', 18]]] так что вам нужно манипулировать каждый элемент в списке и принимать только второй индекс, это можно сделать с помощью функции map:

[map(lambda a:a[0],list(v)) for k, v in itertools.groupby(X, lambda x: x[1] == 0) if not k] 
+0

Это действительно уродливое и непрозрачное сочетание itertools, понимание списка, функциональные идиомы и выражения лямбда. Я знаю, что вы правы, но я не могу в хорошей совесть продвигать этот код, если вы не разделите его на несколько строк и не сделаете его читаемым. Ваш код не требует такого объяснения, если вы не пытаетесь втиснуть его в одну строку. Просто используйте описательные имена. –

+0

Я не думаю, что они делают то, что он ожидает, где это «Y = [[[a, 2], [b, 12], [c, 6]], [[e, 2]], [ [h, 12], [i, 18]]] '? – Netwave

+0

@machineyearning Я попытался найти решение как можно более похожее на то, что он пытался сделать, может быть, я добавлю лучшее решение, если найду его – Elisha

0

Я буду делать это так:

X = [ ['a',2], ['b',12], ['c',6], ['d',0], ['e',2], ['f',0], ['g',0], ['h',12], ['i',18] ] 
ind = [-1] + [i for i in range(n) if X[i][1]==0] + [len(X)] # found the indices of the "zero" lists 
Y = [X[ind[i]+1:ind[i+1]] for i in range(len(ind)-1)] # choose the items between those indices 
Y = [[x[0] for x in list] for list in Y] # take only X[0] 
Y 
#output 
[['a', 'b', 'c'], ['e'], [], ['h', 'i']] 

Он просто обнаружил «нулевые» индексы, а затем использовал срезы для получения правильных списков списков.

Конечно, вы можете удалить пустые списки в конце.

1

Вы можете определить свой собственный разветвитель с помощью итератора:

def splitter(L): 
    group = [] 
    res = [] 
    for i in iter(L): 
     if i[1]: 
      group.append(i[0]) 
     if not i[1] and len(group): 
      res.append(group) 
      group = [] 
    if len(group): 
     res.append(group) 
    return res 

#In [62]: splitter(X) 
#Out[62]: [['a', 'b', 'c'], ['e'], ['h', 'i']] 

Если вы работаете с персонажами, здесь подход - несмотря я предпочитаю разветвитель для конкретной задачи:

[list(u) for u in ''.join([i[0] if i[1] else '|' for i in X]).split("|") if u] 
#[['a', 'b', 'c'], ['e'], ['h', 'i']] 

I также улучшит/сократит @Elisha ответ с небольшим взломом:

from itertools import groupby 

[list(zip(*v)[0]) for k, v in groupby(X, lambda x: x[1] == 0) if not k] 
+0

Самый короткий! = Лучший. Это код, который не нуждается в комментариях и легко следовать. Но почему 'iter (L)', где будет выполняться обычный 'L'? Лично предпочтет «len (group)! = 0' в тестах: делает его еще проще для чтения, хотя функционально идентичным. – nigel222

+0

iter (L) является рефлексом, так как я обычно использую итераторы. Я думаю, что 'len (group)' более явственно, чем 'if i [1]' :) Но да, вы правы, можно было прямо указать условие. –