开发者

implementing multiple string replace() using lambda function

I've found tons of solutions doing exactly what I'm trying to do WITHOUT lambda...but I'm learning lambda today...

I have a string stri and I'm trying to replace some characters in stri that are all stored in a dictionary.

bad_chars={"\newline":" ","\n": " ", "\b":" ", "\f":" ", "\r":" ", "\t":" ", "\v":" ", "\0x00":" "} and then I want to print stri out all pretty and empty of all of these ugly characters. My current code print's stri many many times.

format_ugly = lambda stri: [ stri.replace(i,j) for i,j in bad_chars.iteritems()]

Is there a way to make it print开发者_JAVA百科 once, and with only 1 lambda function?


If you really want to you can force a lambda function into it:

print ''.join(map(lambda x: bad_chars.get(x, x), stri))

But really there's absolutely no need to use a lambda function here. All you need is:

print ''.join(bad_chars.get(x, x) for x in stri)

This solution is also linear time (ie O(n)) whereas all the other solutions are potentially quadratic as they involve scanning the entire string to replace each value O(n*m) where m is the size of the bad_chars dict.

Example:

bad_chars= {"\newline":" ","\n": " ", "\b":" ", "\f":" ", "\r":" ", "\t":" ", "\v":" ", "\0x00":" "}
stri = "a \b string\n with \t lots of \v bad chars"
print ''.join(bad_chars.get(x, x) for x in stri)

Ouptut:

a   string  with   lots of   bad chars


You can't really do it that easily and if you could a lambda function is still not designed for your use case.

Multiple replacements like that are done using a regular for loop statement, and a lambda is limited to a single expression. If you have to use a function, use a normal function – it's entirely equivalent to a lambda function except that it's not limited to a single expression.

If you really must know how to do it in a single expression, you have three choices:

1) If you use unicode strings (or Python 3), and limit your bad substrings to single characters (i.e. remove "\newline"), you can use the unicode.translate method.

bad_chars = {u"\n": u" ", u"\b": u" ", u"\f": u" ", u"\r": u" ", u"\t": u" ", u"\v": u" ", u"\x00": u" "}
bad_chars_table = dict((ord(k), v) for k, v in bad_chars.iteritems())
translator = lambda s: s.translate(bad_chars_table)
print translator(u"here\nwe\tgo")

2) Use regular expressions:

   translator = lambda s: re.sub(r'[\n\b\f\r\t\v\x00]', ' ', s)

3) You can use reduce which can be used to reduce a sequence using a binary operation, essentially repeatedly calling a function of two arguments with the current value and an element of the sequence to get the next value.

translator = lambda s: reduce(lambda x, (from, to): x.replace(from, to), bad_chars.iteritems(), s)

As you can see, the last solution is much more difficult to understand than:

def translator(s):
    for original, replacement in bad_chars.iteritems():
        s = s.replace(original, replacement)
    return s

And both solutions do the same thing. It's often better to program for the end, not for the means. For an arbitrary problem a comprehensible single-expression solution wouldn't exist at all.


You shouldn't produce a list of the values. Your code produces a list of values with the original text with only one character replaced (one per version). Instead operate on the result of one entry and pass it for the next. This is pretty much what reduce does:

replaced = reduce(lambda stri, r: stri.replace(r[0], r[1]), bad_chars.iteritems(), original)

this is roughly equivalent to:

stri.replace(r0[0], r0[1]).replace(r1[0], r1[1]).replace(...)

where r0..rn are the values from bad_chars.iteritems().

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜