كيفية تحويل إدخال ملف تسلسل Dumbo إلى TAB SPALED TEXT
سؤال
لدي مدخلات ، والتي يمكن أن تكون بدائية واحدة أو قائمة أو tuple من البدائية.
أرغب في تسطيحه إلى قائمة فقط ، مثل ذلك:
def flatten(values):
return list(values)
ستكون الحالة العادية متسقة (SomeIterablethatis nostastring)
ولكن إذا كانت القيم = '1234' ، فسأحصل على ['1' ، '2' ، '3' ، '4'] ، لكنني أريد ['1234'
وإذا كان القيم = 1 ، فسأحصل على نوع typeerror: كائن "int" غير أمر لا يطاق ، لكنني أريد [1
هل هناك طريقة أنيقة للقيام بذلك؟ ما أريد فعله حقًا في النهاية هو مجرد "
تحرير: دعني أشرح هذا بشكل أفضل ...
أرغب في تحويل ملف تسلسل ثنائي Hadoop إلى ملف نصي منفصل عن علامة تبويب مسطحة باستخدام Dumbo. باستخدام خيار تنسيق الإخراج ، نص outputformat
Dumbo هو غلاف Python حول تدفق Hadoop. باختصار ، أحتاج إلى كتابة وظيفة Mapper:
Def Mapper (مفتاح ، قيم) #بعض الأشياء العائد K ، V
حيث K عبارة عن سلسلة من الجزء الأول في المفتاح ، والقيمة عبارة عن سلسلة مفصولة مفصولة تحتوي على بقية المفتاح والقيم كسلاسل.
على سبيل المثال:
input: (123, [1,2,3])
output: ('123', '1\t2\t\t3')
أو أكثر تعقيدًا:
input: ([123, 'abc'], [1,2,3])
output: ('123', 'abc\t1\t2\t\t3')
يمكن أن يكون مفتاح الإدخال أو القيمة بدائية أو قائمة/tuple من الدالة الأولية التي أرغب في وظيفة "Flatten" التي يمكن أن تتعامل مع أي شيء ، وإرجاع قائمة القيم.
للحصول على القيمة الخارجية ، سأفعل شيئًا مثل هذا v = ' t'..
المحلول
يبدو أنك تريد itertools.chain()
. ستحتاج إلى سلاسل خاصة ، لأنها في الحقيقة مجرد تكرار من الشخصيات.
تحديث:
هذه مشكلة أبسط بكثير إذا قمت بذلك كمولد متكرر. جرب هذا:
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
هذا يعيد جهاز التكرار بدلاً من القائمة ، ولكن يتم تقييمه بتكاسل ، وهو ما تريده على أي حال. إذا كنت بحاجة حقًا إلى قائمة ، فما عليك سوى الاستخدام list(flatten(seq))
في حين أن.
تحديث 2:
كما أشار الآخرون ، إذا كان ما تريده حقًا هو تمرير هذا str.join()
, ، ستحتاج إلى تحويل جميع العناصر إلى سلاسل. للقيام بذلك ، يمكنك إما استبدال yield foo
مع yield str(foo)
خلال المثال الخاص بي أعلاه ، أو استخدم رمزًا مثل ما يلي:
"\t".join(str(o) for o in flatten(seq))
نصائح أخرى
بناءً على سؤالك المتكرر ، هذا mapper
قد تفعل الوظيفة ما تريد:
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()
يبدو أنك ربما تريد تغيير ذلك return
إلى yield
. يفترض هذا أيضًا أن مفتاح الإدخال سيكون دائمًا عنصرًا واحدًا أو قائمة بالعناصر (وليس قائمة القوائم) وأن قيم الإدخال ستكون دائمًا قائمة بالعناصر (مرة أخرى ، وليس قائمة القوائم).
هل يلبي ذلك متطلباتك؟
يجب أن أقول إن المتطلبات المعلنة غريبة ، ولا أعتقد تسطح هو الاسم الصحيح لهذا النوع من العملية. ولكن إذا كنت كذلك حقًا تأكد من أن هذا ما تريده ، فهذا ما يمكنني التمييز عنه من سؤالك:
>>> 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'