0

I have a list strings that look like this:

strings = ["abc", "a", "AA", "DAabcas", "adesAA", "EFSFDAAAaaa"]

I also have an already existing function that goes through every element in the list and returns the number of capital letters in each string element:

capitals = 0

for i in s:
    if i.isupper():
        capitals += 1
return capitals

"s" is each item in strings.

How can i use this to return the list strings sorted descending with the string with the most capital letters first, and the shortest word with the least or none capital letters?

Here is the result i want:

strings = ["EFSFDAAAaaa","DAabcas","adesAA", "AA", "abc", "a"]

Thanks.

Mert Köklü
  • 2,183
  • 2
  • 16
  • 20

5 Answers5

1

Following is just another method to do it.

strings.sort(key=lambda x:(numCapitals(x), len(x)), reverse=True) # a better way 
Khushit Shah
  • 546
  • 6
  • 20
1

list.sort with a proper key function:

strings.sort(key=lambda s: (sum(map(str.isupper, s)), len(s)), reverse=True)
# ['EFSFDAAAaaa', 'DAabcas', 'adesAA', 'AA', 'abc', 'a']
user2390182
  • 72,016
  • 6
  • 67
  • 89
0

Using your code there's is an ambiguity in the output. Substrings: "DAabcas" and "AA" both have two capital letters. We can use a second factor to break ties, such as the string length (len).

def count_capitals(s):
  capitals = 0

  for i in s:
    if i.isupper():
      capitals += 1
  return capitals

strings = ["abc", "a", "AA", "DAabcas", "adesAA", "EFSFDAAAaaa"]

# Use your function as a [sorting key](https://www.geeksforgeeks.org/sorted-function-python/)
s = sorted(strings, key = lambda x: (count_capitals(x), len(x)), reverse=True)
print(s)

Output

['EFSFDAAAaaa', 'DAabcas', 'adesAA', 'AA', 'abc', 'a']
DarrylG
  • 16,732
  • 2
  • 17
  • 23
0

Regarding How to sort using multiple criterias, here the number of capital and the length you may do

def count_capitals(word): # just a shorter way
    return len([_for _in word if _.isupper()])

if __name__ == '__main__':
    strings = ["abc", "a", "AA", "DAabcas", "adesAA", "EFSFDAAAaaa"]
    result = sorted(strings, key=lambda e: (count_capitals(e), len(e)), reverse=True)


    # Using another computation and inline it
    result = sorted(strings, key=lambda e: (sum(_.isupper() for _ in e), len(e)), reverse=True)

To compare with the answers given by the others (using timeit on 1000000 iterations) result are just same (https://pastebin.com/T0m3TDp7) :

sum([1 for _ in word if _.isupper()]) 0.1112008
len([1 for _ in word if _.isupper()]) 0.11526590000000003
len([_ for _ in word if _.isupper()]) 0.11423499999999998
len([c for c in word if c.isupper()]) 0.12964770000000003
sum(_.isupper() for _ in word)        0.11216479999999997
sum(map(str.isupper, s))              0.112989
azro
  • 53,056
  • 7
  • 34
  • 70
  • Your `count_capitals` there is better off as `return sum(ch.isupper() for ch in word)`... and then you could even inline that as a gen-exp if wanted, so something like: `result = sorted(strings, key=lambda e: (sum(ch.isupper() for ch in e), len(e)), reverse=True)` if wanted...` – Jon Clements Nov 10 '19 at 14:21
  • @JonClements sure , but difference is nothing here https://pastebin.com/T0m3TDp7 – azro Nov 10 '19 at 14:28
  • For pretty much all cases as per the OPs problem there won't be a difference... however, say you had 100mb strings... there's no need to build up a temporary list of all the upper case characters just to take its length... (so performance wise it's not going to differ massively, but memory overhead it could be significant... although in most cases - it won't matter) – Jon Clements Nov 10 '19 at 14:33
  • For instance... try editing your 3rd and 5th timeit examples using `string.ascii_uppercase * 1000000` as the source string... the difference should be much more noticeable then – Jon Clements Nov 10 '19 at 14:39
  • @JonClements the difference is just super small, but ok lol I won't gain upvote fir this^^https://pastebin.com/M9ue887t even I'm the only one that talked about multi criteria sort :D – azro Nov 10 '19 at 14:50
  • Umm... you've got `"string.ascii_uppercase * 1000000"` - that's not the same as `string.ascii_uppercase * 1000000` :) – Jon Clements Nov 10 '19 at 15:00
  • @JonClements my bad, but still quite same https://pastebin.com/2pqWzrwe even with a 1m tries difference chances at every test, one code is not super better than the others – azro Nov 10 '19 at 15:03
-1

Well this question looks like you're stuck on a introductory programming course problem. Okay so you already have you sorting criteria code (well done), let's extract that to a function:

>>> def capcount(s):
...   capitals = 0
...   for i in s:
...     if i.isupper():
...       capitals+=1
...   return capitals

# but in python this can be translated to:

lambda s: sum(1 for c in s if c.isupper())

Now you can use this function as the key parameter of the builtin sorted:

strings = ["abc", "a", "AA", "DAabcas", "EFSFDAAAaaa", "adesAA"]
sorted(strings, key = lambda s: sum(1 for c in s if c.isupper()))
==> ["abc", "a", "AA", "DAabcas", "adesAA", "EFSFDAAAaaa"]

So this is ordered the opposite way you want it, now you can do one of two things (probably more):

# Invert what you have now
min_to_max = sorted(strings, key = lambda s: sum(1 for c in s if c.isupper()))
max_to_min = min_to_max[::-1]

# Or change the sorting function around
# lambda s: sum(-1 for c in s if c.isupper())
max_to_min = sorted(strings, key = lambda s: sum(-1 for c in s if c.isupper()))
Esser420
  • 780
  • 1
  • 8
  • 19