3

I have a list of tuples with each tuple containing two values. The first value is a list of strings, the second value is a string:

list_of_tuples = [(['this', 'askjsdaddsa', 'match1'], 'done'), (['sajs', 'skasassas', 'asdasdasdasd', 'qwerty'], 'doneagain')]

How can I reduce the first value within the tuple to only the strings that contain six letters? Ideally I would have

final_list_of_tuples = [('match1' , 'done'), ('qwerty', 'doneagain')]

So far I have the following:

for a, b in dict_refine:
    a.remove(i for i in a if len(i) != 6)

I feel as if there is something very elementary that I am blowing right past. Is there a way to do this in one line? Would it be easier to output into a dictionary?

JRR
  • 578
  • 5
  • 21
  • 1
    Given your explanation, is there a mistake in your expected output? I would expect you mean: `final_list_of_tuples = [(['match1'] , 'done'), (['qwerty'], 'doneagain')]`, or do you mean to assume there will only be one that is six letters long? – Gareth Latty Jun 22 '18 at 01:57
  • what if more than two words have exactly six characters ? – Venkata Gogu Jun 22 '18 at 01:58
  • @GarethLatty I do not mind if it is a one item list or an integer on its own. – JRR Jun 22 '18 at 01:59

3 Answers3

3

As with most tasks involving changing a list in Python, the tool for the job here is probably the list comprehension, in this instance, two of them:

>>> [([word for word in words if len(word) == 6], key) for (words, key) in list_of_tuples]
[(['match1'], 'done'), (['qwerty'], 'doneagain')]

The inner comprehension [word for word in words if len(word) == 6] is hopefully clear - this filters the list down to words of length six. The outer one just applies that inner one to the first element of each tuple and reconstructs the tuple.

If you are working directly with the values, of course, there is no need to construct a new list, you can just iterate normally:

for (words, key) in list_of_tuples:
    six_letter_words = [word for word in words if len(word) == 6]
    ....
Gareth Latty
  • 86,389
  • 17
  • 178
  • 183
2

If you want to support multiple 6 letter strings on those lists you may use:

>>> l = [(['this', 'askjsdaddsa', 'match1'], 'done'), (['sajs', 'skasassas', 'asdasdasdasd', 'qwerty'], 'doneagain')]
>>> [([x for x in a if len(x) == 6], b) for a, b in l]
[(['match1'], 'done'), (['qwerty'], 'doneagain')]

You can also fetch the first 6 letter string on the string lists:

>>> l = [(['this', 'askjsdaddsa', 'match1'], 'done'), (['sajs', 'skasassas', 'asdasdasdasd', 'qwerty'], 'doneagain')]
>>> [(next(x for x in a if len(x) == 6), b) for a, b in l]
[('match1', 'done'), ('qwerty', 'doneagain')]

As you mentioned using a dict, it is also possible:

>>> l = {'done': ['this', 'askjsdaddsa', 'match1'], 'doneagain': ['sajs', 'skasassas', 'asdasdasdasd', 'qwerty']}
>>> {k: [x for x in v if len(x) == 6] for k, v in l.items()}
{'done': ['match1'], 'doneagain': ['qwerty']}

If you want only the first 6 letter word using this approach you may use:

>>> l = {'done': ['this', 'askjsdaddsa', 'match1'], 'doneagain': ['sajs', 'skasassas', 'asdasdasdasd', 'qwerty']}
>>> {k: next(x for x in v if len(x) == 6) for k, v in l.items()}
{'done': 'match1', 'doneagain': 'qwerty'}

Personally I prefer the dict approach since it looks cleaner.

bla
  • 1,840
  • 1
  • 13
  • 17
1

You can use list comprehensions - elem below stands for element of your list.

[([i for i in elem_list if len(i) == 6], elem_str) for (elem_list, elem_str) in list_of_tuples]

a simpler example for list comprehension would be :

[i for i in range(6)] , this will create a list from 0 to 5. Functions can be easily applied instead of just i . Here's a good reference. You can use this syntax in dictionaries as well, for basic string manipulation ''.join() is useful . Explanation of how list comprehension works?

pyeR_biz
  • 986
  • 12
  • 36