3

I have such list:

setter_maping = ['14.99', '0.0', '226.95', '0.0', '14.99', 'None', '0.0']

How can I get such list (to remove all duplicates, zeros, Nones... in one word : to remove all what is not float number like 22.22 or 15.66 etc, if I will have there 0.0, or any thing that is not compatible with pattern of number.number (11.1 , 11.11) such value should be deleted):

result = ['14.99', '226.95']

I have done simple:

kick_off = ['None', '0.0']
[mapped_prices.remove(i) for i in set_map if i in kick_off]

But how to produce more unified pattern for removing wrong values? Can regex provide me solution? which regex will solve this? I have no experience with this module

smith
  • 371
  • 2
  • 5
  • 14

4 Answers4

4

This will work for any non-float value, not only None or 'None', and will also preserve the original order:

set_map = ['17.99', '0.0', '26.95', '26.95', '17.99', 'None', '0.0']
seen = {0}
new_map = []
for item in set_map:
     try:
         flitem = float(item)
     except ValueError:
         continue
     if flitem not in seen:
         seen.add(flitem)
         new_map.append(item)

print(new_map)

Additionally, strings such as '0' or '0.000000' won't make it into the new list.

timgeb
  • 76,762
  • 20
  • 123
  • 145
  • vise solution @timgeb , I forgot to say that I need always 2 item in result, but your variant works well – smith Jul 13 '14 at 17:00
  • This is exactly doing what the OP specified, I'd like the downvote to be explained, thanks. – timgeb Jul 13 '14 at 17:06
  • Seems a bit long for a pretty simple problem. Why use 11 lines of more complicated code when you could use 4? Also, this doesn't solve OPs problem. He asked for strings in the output. You're giving him floats. – Eli Jul 13 '14 at 17:19
  • 1
    @Eli ah, thanks for pointing out that there are strings in the expected result, I overlooked that. I adjusted my code accordingly. In addition, your solution using a set is better if the original order does not need to be preserved, but I was of the impression that it should be preserved. I also assumed that there can be mutable objects in the original list, then a TypeError will be thrown when you try to make it a set. – timgeb Jul 13 '14 at 17:33
3

Use a set to remove duplicates, then remove anything else you don't want:

import re
result = set(['17.99', '0.0', '26.95', '26.95', '17.99', 'None', '0.0'])
result = [item for item in result if re.match('\d+\.\d+$', item)]
result = [item for item in result if float(item) != 0.0]
Eli
  • 36,793
  • 40
  • 144
  • 207
  • I wasn't the down vote, but maybe I can give some feedback. The comparison of `None` and `'None'` is False. – MrAlias Jul 13 '14 at 16:50
  • Fixed, thanks. Didn't realize it wasn't literal. Still don't get why down vote and not just comment with that. – Eli Jul 13 '14 at 16:51
  • @Eli thanks, but what if there will be 17.999 in values along with 17.99, I need to have 2 values in result all time – smith Jul 13 '14 at 16:53
  • @Eli I have tested this and your solution not provides now result what I need – smith Jul 13 '14 at 16:56
  • 1
    This feels a little limited. What about '0.00'? – timgeb Jul 13 '14 at 16:57
  • @smith: I don't see that part in your question. Can you explain what you want to happen in situations where your rules would return more than 2 items? – Eli Jul 13 '14 at 16:57
  • @Eli when Im running your code, Im getting in result 17.99 and 0.0 , need 17.99 and 26.95 – smith Jul 13 '14 at 17:05
  • @Eli sorry, now with regexp much better – smith Jul 13 '14 at 17:07
  • 1
    @timgeb true. didn't realize he meant there would be other stuff of the sort there. Fixed to account for anything equal to 0. Still just 4 lines. – Eli Jul 13 '14 at 17:07
  • @smith try now. Anything missing? – Eli Jul 13 '14 at 17:08
  • @Eli no, works well , but why are u using result as a name 2 times for comprehension? – smith Jul 13 '14 at 17:12
  • @smith to overwrite it in memory. Shouldn't matter much if your list is small, so in that case you could use different names to improve readability. – Eli Jul 13 '14 at 17:17
  • nitpicking: won't work if there can be mutable objects in the original list, but I assume that is not the case here. Good answer if the order of the result is irrelevant. – timgeb Jul 13 '14 at 17:36
  • 1
    This fails on an input of `1.2e+19`. Regex for this task is using a sledgehammer to swat flies. – msw Jul 13 '14 at 17:47
  • @msw there was no indication OP would be using anything like that, and he specifically asked for Regex. If he had to deal with complex representations like in your example, I'd agree with you, but if not, I'd prefer to keep the code short and simple as above. – Eli Jul 13 '14 at 18:53
2

@timgeb: Your Answer is accurate, but you can use just set:

set_map = ['17.99', '0.0', '26.95', '26.95', '17.99', 'None', '0.0']
new_map = []
for item in set(set_map):
    try:
        item = float(item)
        if item > 0: new_map.append(item)
    except ValueError:
        continue

new_map
Devashish Das
  • 241
  • 7
  • 19
1
  • Convert to floats to get rid of ambiguities in text representation ('12.34' versus '0012.3400')
  • Use a for because exceptions may need to be caught
  • Use a set to filter out duplicates.

Usually I'd prefer a list comprehension, but that doesn't work well with having to catch exceptions. In this case for the float() conversion.

In [1]: data = ['17.99', '0.0', '26.95', '26.95', '17.99', 'None', '0.0']

In [2]: nw = set()

In [3]: for j in data:
   ...:     try:
   ...:         k = float(j)
   ...:         if k:
   ...:             nw.add(k)
   ...:     except ValueError:
   ...:         pass
   ...:     

In [4]: print nw
set([0.0, 26.95, 17.99])

In [5]: list(nw)
Out[5]: [0.0, 26.95, 17.99]
Roland Smith
  • 42,427
  • 3
  • 64
  • 94
  • This does not preserve the original order (I'm not sure that's a requirement, but I think it is) and still contains a 0.0. – timgeb Jul 13 '14 at 17:03