-1

is there a way to convert the below statements to one list comprenshion

def find_gender(gender_data):
    gender = {
        "Women": ["women", "women's", "female"],
        "Men": ["men", "men's", "male"],
    }
    gender_data = gender_data.lower()
    for gender_key, gender_items in gender.items():
        for word in gender_items:
            if gender_data.find(word) is not -1:
                return gender_key
    return "Unisex"

the output should be only one string i.e 'Men' or 'Women' or 'Unisex'

Tadhg McDonald-Jensen
  • 20,699
  • 5
  • 35
  • 59
  • 4
    If you want a single value as a result, a list comprehension seems like an odd tool to use. – Chris Aug 28 '22 at 18:33
  • 1
    the answer is no, because the return value is not a list – njzk2 Aug 28 '22 at 18:33
  • 2
    You might rather want to have an "inverted" version of the dict, like `{"women": "Women", "women's": "Women", "female": "Women", "men": "Men", ...}`. – j1-lee Aug 28 '22 at 18:39
  • 3
    As a side note: **don't** use `is` to check for equality. `if gender_data.find(word) is not -1:` should be `if gender_data.find(word) != -1:`. You were just lucky that this works in this very specific case because of some implementation detail - see https://stackoverflow.com/questions/306313/is-operator-behaves-unexpectedly-with-integers – Thierry Lathuille Aug 28 '22 at 18:57
  • See my answer for usage of `any()` and list comprehensions to avoid loops. – Claudio Aug 28 '22 at 19:14

2 Answers2

0

As you want a single result, a list comprehension is a poor choice of tool. However, we can readily directly translate your loops into a generator expression, and pass that to next, providing a default value of 'Unisex'.

def find_gender(gender_data):
    gender = {
        "Women": ["women", "women's", "female"],
        "Men": ["men", "men's", "male"],
    }
    gender_data = gender_data.lower()
    
    return next((gender_key 
                 for gender_key, gender_items in gender.items() 
                 for word in gender_items
                 if gender_data.find(word) is not -1),
                'Unisex')
Chris
  • 26,361
  • 5
  • 21
  • 42
  • 2
    `if gender_data.find(word) is not -1` should be `if gender_data.find(word) != -1:`, see my comment under the question; – Thierry Lathuille Aug 28 '22 at 18:59
  • 1
    Agreed. I was providing a direct translation of the OP's code. Warts and all. – Chris Aug 28 '22 at 19:00
  • Would you be so kind to provide more explanations about your code? I feel lost ... don't understand what the code does. I can run it and see that it works, but I don't grasp how it comes that it works. – Claudio Aug 28 '22 at 19:49
  • The generator expression passed to `next` she's exactly what the nested for loops and conditional of the OP do. It iterates over matches. The `next` function find the _first_ such match. If one doesn't exist, the default value of `'Unisex'` is returned. – Chris Aug 28 '22 at 21:08
-1

Code below uses two list/generator comprehensions and the any() method. And with changed data structure achieves in my eyes a simple self-explaining and short structure.

def find_gender(gender_data): 
    gender_data = gender_data.lower()
    woman = ["women","women's","female"]
    man   = ["men"  ,"men's"  ,"male"  ]
    if any(s for s in woman if s in gender_data): return "Woman"
    if any(s for s in man   if s in gender_data): return "Men"
    return "Unisex"
Claudio
  • 7,474
  • 3
  • 18
  • 48
  • 1
    Passing list comprehensions to `any` is less efficient than passing generator expressions. Using a flat list of words and having to code `3` twice is fairly brittle compared to the OP's approach. – Chris Aug 28 '22 at 19:14
  • @Chris : I have changed the code. Is it what you were speaking about? – Claudio Aug 28 '22 at 19:18
  • 1
    Your code is substantially more brittle than the OP's. Adding other genders and other keywords would require changing your code extensively rather than just updating one dictionary. This is why I have downvoted. – Chris Aug 28 '22 at 19:22
  • If I have got you right the newest version of the code above does not have the issues you mentioned. Or am I still missing something? – Claudio Aug 28 '22 at 19:26
  • It still lacks the ability to make changes to a single dictionary to add terms, and the name of each gender. The nested loop is gone, but because you have essentially unrolled the outer loop and written each iteration separately. If the logic of the inner loop were to change, you would have to make two changes to your code rather than one. – Chris Aug 28 '22 at 21:34
  • Sorry, but can't follow your argumentation at all. I see the total opposite to be true. If the points of view are too far away a discussion doesn't make much sense. You like your and I prefer my way of doing things. Thanks for the hints and the help with improving my code :) . – Claudio Aug 28 '22 at 21:39