Francesco Martini
Francesco Martini

Reputation: 1

Is there a way to shorten my code and avoid extension and condition repetition? I'm trying the problem set "extensions" from CS50

file = input("File name: ").strip().lower()

extension_image = (".gif",".jpg", ".jpeg",".png")
extension_application = (".pdf","zip")
extension_text = ("txt")

condition_image = file.endswith(extension_image)
condition_application = file.endswith(extension_application)
condition_text = file.endswith(extension_text)

if condition_image == True:
    normal = file.split(".")
    print("image/" + str(normal[-1]))
elif condition_application == True:
    normal = file.split(".")
    print("application/" + str(normal[-1]))
elif condition_text == True:
    normal = file.split(".")
    print("text/" + str(normal[-1]))
else:
    print("application/octet-stream")

File take as an input the name and the extension and i should replace the extension like (.pdf) with the type of fyle slash the extension.

Upvotes: -1

Views: 120

Answers (3)

Serhii Fomenko
Serhii Fomenko

Reputation: 1055

Based on your solution, I would rework it like this:

extension_groups = (
    ('.gif', '.png', '.jpeg', '.jpg'),
    ('.pdf', '.zip'),
    ('.txt',),
)
group_names = ('image', 'application', 'text')
file = 'someFileName.jpeg'
for extensions, name in zip(extension_groups, group_names):
    if file.endswith(extensions):
        _, extension = file.rsplit('.', 1)
        print(f'{name}/{extension}')
        break
else:
    print('application/octet-stream')

Here, I use the dict object to keep all extension groups as keys and their names as values. In addition to this, a not-so-familiar construct is used:

for _ in iterable:
    ...
else:
    ...

The point is that else at the end of the loop will work only if the break operator did not work in the loop. In our case, if we have not found a matching file extension.

As an alternative, I can offer you a different solution based on regular expression, it looks like this:

import re

search_pattern = re.compile(
    r'^.*\.(?:'
    r'(?P<image>gif|png|jpe?g)'
    r'|(?P<application>pdf|zip)'
    r'|(?P<text>txt)'
    r')$'
)

file = 'someFileName.jpeg'
if (match_obj := search_pattern.match(file)) is None:
    print('application/octet-stream')
else:
    match_items = match_obj.groupdict().items()
    print(next(f'{k}/{v}' for k, v in match_items if v is not None))

If we didn't find a valid file extension match_obj == None, otherwise we get all the named groups as a dict object, like this {'image': 'jpeg', 'application': None, 'text': None}, in which we just need to find the group that was found.

UPDATED

Even though you completely ignored my reply. And no restrictions were stated in your question about using loops. Here is the solution (I just rewrote yours), which is now almost unreadable, but it is as concise as possible (if you count lines of code), + loops are not used. But keep in mind that it is better not to abuse it. In this case, brevity is NOT the sister of talent!

file = input("File name: ").strip().lower()
ext_img, ext_app, ext_text = (".gif", ".jpg", ".jpeg", ".png"), (".pdf", "zip"), (".txt",)
is_img, is_app, is_text = file.endswith(ext_img), file.endswith(ext_app), file.endswith(ext_text)
ext = file.split(".")[-1]
print((is_img and 'image/' + ext) or (is_app and 'application/' + ext) or (is_text and 'text/' + ext) or 'application/octet-stream')

If you take just your solution it can also be greatly reduced and simplified, for example, like this:

file = input("File name: ").strip().lower()

extension_image = (".gif",".jpg", ".jpeg",".png")
extension_application = (".pdf","zip")
extension_text = ("txt")

condition_image = file.endswith(extension_image)
condition_application = file.endswith(extension_application)
condition_text = file.endswith(extension_text)
normal = file.split(".")[-1]
if condition_image:
    print("image/" + normal)
elif condition_application:
    print("application/" + normal)
elif condition_text:
    print("text/" + normal)
else:
    print("application/octet-stream")
  1. There's no point in doing normal = file.split, if the conditions are met, this should be moved up.
  2. If the condition checks for True you should not write if condition == True, just use if condition (it's the same thing), for example in your case if condition_image.
  3. You don't need to cast to the string str(normal[-1]) every time. normal is a list in which all elements are strings. Just use normal[-1].

Or here's a variant based on @Swifty's answer, but without using dict comprehension and if/else.

ext_reversed = {
    'gif': 'image', 'jpg': 'image', 'jpeg': 'image', 'png': 'image',
    'pdf': 'application', 'zip': 'application', 'txt': 'text',
}
file = input("File name: ").strip().lower()
ext = file.split(".")[-1]
print(((name := ext_reversed.get(ext)) and name + f'/{ext}') or 'application/octet-stream')

Upvotes: 0

Swifty
Swifty

Reputation: 3429

I'd turn your three extension_... into one dictionary (and fix the naming inconsistencies at the same time: . sometimes there, sometimes not...), then use a reversed dictionary to construct the messages:

extensions = {
    "image": ("gif", "jpg", "jpeg", "png"),
    "application": ("pdf", "zip"),
    "text": ("txt",)
}

extensions_reversed = {value: key for key, values in extensions.items() for value in values}


file = input("File name: ").strip().lower()
this_extension = file.split(".")[-1]

if this_extension in extensions_reversed:
    print(f"{extensions_reversed[this_extension]}/{this_extension}")
else:
    print("application/octet-stream")

Upvotes: 0

nbk
nbk

Reputation: 49410

You could use or between your conditions as it is enough if one of the conditions is true to run your code

extension_image = (".gif",".jpg", ".jpeg",".png")
extension_application = (".pdf","zip")
extension_text = ("txt")

condition_image = file.endswith(extension_image)
condition_application = file.endswith(extension_application)
condition_text = file.endswith(extension_text)

if condition_image == True or condition_application == True or condition_text == True:
    normal = file.split(".")
    print("text/" + str(normal[-1]))
else:
    print("application/octet-stream")

Upvotes: 0

Related Questions