Cómo convertir la entrada del archivo de secuencia dumbo a texto separado por tabulaciones

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

  •  06-07-2019
  •  | 
  •  

Pregunta

Tengo en entrada, que podría ser una primitiva única o una lista o tupla de primitivas.

Me gustaría aplanarlo a una lista, así:

def flatten(values):
    return list(values)

El caso normal se aplanaría (algo así como una cadena)

Pero si values ??= '1234', obtendría ['1', '2', '3', '4'], pero querría ['1234']

Y si valores = 1, obtendría TypeError: el objeto 'int' no es iterable, pero me gustaría [1]

¿Hay una manera elegante de hacer esto? Lo que realmente quiero hacer al final es simplemente '\ t'.join (flatten (values))

Editar: Déjame explicarte esto mejor ...

Deseo convertir un archivo de secuencia binaria hadoop en un archivo de texto separado por tabulaciones planas usando dumbo. Usando la opción de formato de salida, -outputformat text

Dumbo es un envoltorio de python para la transmisión de hadoop. En resumen, necesito escribir la función de mapeador:

def mapper (clave, valores)     #hacer algunas cosas     rendimiento k, v

donde k es una cadena de la primera parte de la clave, y el valor es una cadena separada por tabulaciones que contiene el resto de la clave y los valores como cadenas.

por ejemplo:

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

o más complicado:

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

La clave o valor de entrada puede ser una primitiva o una lista / tupla de primitivas Me gustaría un "aplanar" función que puede manejar cualquier cosa y devolver una lista de valores.

Por el valor de salida, haré algo como esto v = '\ t'.join (list (str (s) for s in flatten (seq)))

¿Fue útil?

Solución

Suena como si quisiera itertools.chain () . Sin embargo, necesitará cadenas de casos especiales, ya que en realidad son solo iterables de caracteres.

Actualización :

Este es un problema mucho más simple si lo haces como un generador recursivo. Prueba esto:

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

Esto devuelve un iterador en lugar de una lista, pero se evalúa de forma perezosa, que probablemente sea lo que desee de todos modos. Si realmente necesita una lista, simplemente use list (flatten (seq)) en su lugar.

Actualización 2 :

Como otros han señalado, si lo que realmente desea es pasar esto a str.join () , entonces deberá convertir todos los elementos en cadenas. Para hacerlo, puede reemplazar yield foo con yield str (foo) en mi ejemplo anterior, o simplemente usar un código como el siguiente:

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

Otros consejos

En función de su pregunta reformulada, esta función mapper podría hacer lo que quiera:

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()

Parece que probablemente querrá cambiar ese return a un rendimiento . Esto también supone que la clave de entrada siempre será un elemento único o una lista de elementos (no una lista de listas) y que los valores de entrada siempre serán una lista de elementos (nuevamente, no una lista de listas).

¿Cumple con sus requisitos?

Debo decir que los requisitos establecidos son extraños y no creo que aplanar sea el nombre correcto para este tipo de operación. Pero si está realmente seguro de que esto es lo que quiere, entonces esto es lo que puedo obtener de su pregunta:

>>> 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'
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top