Come convertire l'input del file di sequenza dumbo in testo separato da tabulazioni

StackOverflow https://stackoverflow.com/questions/1625757

  •  06-07-2019
  •  | 
  •  

Domanda

Ho in input, che potrebbe essere una singola primitiva o un elenco o una tupla di primitivi.

Vorrei appiattirlo in un solo elenco, in questo modo:

def flatten(values):
    return list(values)

Il caso normale verrebbe appiattito (un po 'di errore che non sta dando fastidio)

Ma se valori = '1234', otterrei ['1', '2', '3', '4'], ma vorrei ['1234']

E se valori = 1, otterrei TypeError: l'oggetto 'int' non è iterabile, ma vorrei [1]

Esiste un modo elegante per farlo? Quello che voglio davvero fare alla fine è solo '\ t'.join (appiattisci (valori))

Modifica: mi spiego meglio ...

Vorrei convertire un file di sequenza binaria hadoop in un file di testo separato da tabulazione piatta usando dumbo. Utilizzando l'opzione del formato di output, -outputformat text

Dumbo è un wrapper Python attorno allo streaming hadoop. In breve, devo scrivere la funzione mapper:

def mapper (chiave, valori)     #do alcune cose     resa k, v

dove k è una stringa della prima parte della chiave e value è una stringa separata da tabulazione che contiene il resto della chiave e i valori come stringhe.

es:

input: (123, [1,2,3])
output: ('123', '1\t2\t\t3')

o più complicato:

input: ([123, 'abc'], [1,2,3])
output: ('123', 'abc\t1\t2\t\t3')

La chiave di input o il valore può essere una primitiva o un elenco / tupla di primitive Vorrei un "appiattimento" funzione che può gestire qualsiasi cosa e restituire un elenco di valori.

Per il valore out, farò qualcosa del genere v = '\ t'.join (list (str (s) per s in flatten (seq)))

È stato utile?

Soluzione

Sembra che tu voglia itertools.chain () . Avrai bisogno di stringhe per casi speciali, dato che sono davvero solo iterabili di caratteri.

Aggiorna :

Questo è un problema molto più semplice se lo fai come generatore ricorsivo. Prova questo:

def flatten(*seq):
    for item in seq:
        if isinstance(item, basestring):
            yield item
        else:
            try:
                it = iter(item)
            except TypeError:
                yield item
                it = None
            if it is not None:
                for obj in flatten(it):
                    yield obj

Questo restituisce un iteratore invece di un elenco, ma è valutato pigramente, che è probabilmente quello che vuoi comunque. Se hai davvero bisogno di un elenco, usa invece list (flatten (seq)) .

Aggiornamento 2 :

Come altri hanno sottolineato, se quello che vuoi davvero è passare questo in str.join () , allora dovrai convertire tutti gli elementi in stringhe. Per fare ciò, puoi sostituire yield foo con yield str (foo) nel mio esempio sopra, oppure usare semplicemente un codice come il seguente:

"\t".join(str(o) for o in flatten(seq))

Altri suggerimenti

In base alla tua domanda rinnovata, questa funzione mapper potrebbe fare quello che vuoi:

def mapper(key, values):
    r"""Specification: do some stuff yield k, v where k is a string from the
    first part in the key, and value is a tab separated string containing the
    rest of the key and the values as strings.

    >>> mapper(123, [1,2,3])
    ('123', '1\t2\t3')

    >>> mapper([123, 'abc'], [1,2,3])
    ('123', 'abc\t1\t2\t3')
    """
    if not isinstance(key, list):
        key = [key]
    k, v = key[0], key[1:]
    v.extend(values)
    return str(k), '\t'.join(map(str, v))

if __name__ == '__main__':
    import doctest
    doctest.testmod()

Sembra che probabilmente vorrai cambiare quel ritorno in un rendimento . Ciò presuppone inoltre che la chiave di input sarà sempre un singolo elemento o un elenco di elementi (non un elenco di elenchi) e che i valori di input saranno sempre un elenco di elementi (di nuovo, non un elenco di elenchi).

Soddisfa le tue esigenze?

Devo dire che i requisiti dichiarati sono strani e non credo che appiattire sia il nome giusto per questo tipo di operazione. Ma se sei davvero sicuro che questo è quello che vuoi, allora è quello che posso distillare dalla tua domanda:

>>> import itertools 
>>> def to_list_of_strings(input):
...      if isinstance(input, basestring):   # In Py3k: isinstance(input, str)
...          return [input]
...      try:
...          return itertools.chain(*map(to_list_of_strings, input))
...      except TypeError:
...          return [str(input)]
... 
>>> '\t'.join(to_list_of_strings(8))
'8'
>>> '\t'.join(to_list_of_strings((1, 2)))
'1\t2'
>>> '\t'.join(to_list_of_strings("test"))
'test'
>>> '\t'.join(to_list_of_strings(["test", "test2"]))
'test\ttest2'
>>> '\t'.join(to_list_of_strings(range(4)))
'0\t1\t2\t3'
>>> '\t'.join(to_list_of_strings([1, 2, (3, 4)]))
'1\t2\t3\t4'
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top