-1

I just wanted to know if there is a way to improve this for loop, by skipping those if somehow.

Var String can have more parameters and their order can be casual.
In order to replace the param with a real value, I need :

  1. To split it
  2. To check what parameter is and in which position

Here is a synthetic example on how I thought it:

String = "{FullDate}_{Month}_{Day}_{Year}_{ElementID}_{ElementCD}"
String_split = String.split("_")

for params in range(len(String_split)):

    if "FullDate" in String_split[params]:
        # Do something
    elif "Name" in String_split[params]:
        # Do something
    elif "ElementID" in String_split[params]:
        # Do something
    elif "ElementCD" in String_split[params]:
        # Do something
    elif "Year" in String_split[params]:
        # Do something
    elif "Day" in String_split[params]:
        # Do something
    elif "Month" in String_split[params]:
        # Do something

UPDATE: That's what i would like to accomplish

# Default values
FullDate = now().format("yyyy-MM-dd_HH:mm:ss")
Name = "John"
ElementID = "Apple"
ElementCD = "01Appxz"
Year = now().format("yyyy")
Day = now().format("dd")
Month = now().format("MM")
############################

String = "{FullDate}_{Month}_{Day}_{Year}_{ElementID}_{ElementCD}"
String_split = String.split("_")

for params in range(len(String_split)):

    if "FullDate" in String_split[params]:
        Report_Name = Report_Name + FullDate + "_"
    elif "Name" in String_split[params]:
        Report_Name = Report_Name + Name + "_"
    elif "ElementID" in String_split[params]:
        Report_Name = Report_Name + ElementID + "_"
    elif "ElementCD" in String_split[params]:
        Report_Name = Report_Name + ElementCD + "_"
    elif "Year" in String_split[params]:
        Report_Name = Report_Name + Year + "_"
    elif "Day" in String_split[params]:
        Report_Name = Report_Name + Day + "_"
    elif "Month" in String_split[params]:
        Report_Name = Report_Name + Month + "_"

# Report_Name must return default values, ordered by String variable (eg: FullDate, 1st position; Month 2nd position etc..)
# >> "1999-01-01_10:10:29_01_01_1999_Apple_01Appxz"
# if the String variable changes the params order to
# String = "{Year}_{Month}_{ElementCD}_{FullDate}_{ElementID}_{Day}"
# Report_Name should return
# >> "1999_01_01Appxz_1999-01-01_10:10:29_Apple_01"
Badzlol
  • 1
  • 2
  • 3
    In general, your approach is OK (Python doesn't have a `switch/case` statement, so using `if/elif` or `if/if` chains for this is perfectly pythonic). If your `do something` statement is very similar (e. g. always the same function with different parameters), then you could use a dictionary to do the switching, but readability would probably suffer. – Tim Pietzcker Mar 20 '18 at 08:25
  • I'd say `for param in String_split:` as a starter. But depending on what "Do something" means there could be much more room for optimization. – Klaus D. Mar 20 '18 at 08:27
  • The optimization may be there but your approach is OK. – Rahul Mar 20 '18 at 08:28
  • I don't even think you need a `for` loop, if you don't have some common operation to perform: just check if `anyarg` is in string – Gsk Mar 20 '18 at 08:29
  • If the position of the parameters is relevant, you could use `for num, param in enumerate(String_split):` – a.smiet Mar 20 '18 at 08:31
  • 3
    Reading the question as a whole leads me to believe that this is an XY problem. What are you actually trying to achieve? If all you are trying to do is format the string with arbitrary variables there are better ways to do so. – DeepSpace Mar 20 '18 at 08:32
  • I think you want to go for formatting strings like DeepSpace already mentioned. Read about it [here](https://docs.python.org/2/library/string.html#formatstrings). – Sven-Eric Krüger Mar 20 '18 at 08:33
  • Maybe you can precise what kind of operation you want to do in your `#Do something` ? – David Leon Mar 20 '18 at 08:42
  • See [pyformat.info](https://pyformat.info/) – Peter Wood Mar 20 '18 at 08:42
  • The reason is that i need a for loop to read up the entire splitted string, that will have random parameters inside, separated with "_". Those parameter could go from 0 to X, that's why i'm using a for loop to do so. And yes, the position is relevant, because i have to mount up another string with the actual value of those parameters (Date, elementID etc.). I'd like to skip the dictionary because is not readable as what i wrote, but if you say it'll be faster, then i'll change my approach. Thanks a lot – Badzlol Mar 20 '18 at 08:42
  • 1
    If you have *working code* that you'd like to improve on topics such as readability, maintainability, compatibility, and/or speedability, ask on [codereview.se]. – Jongware Mar 20 '18 at 09:33

2 Answers2

0
  • Use for name in names to remove all your String_split[params] noise.
  • Remove the {} from your variables so you can use == rather than in.
  • Use +=.

This gets:

names = "FullDate Month Day Year ElementID ElementCD".split()
for name in names:
    if "FullDate" == name:
        Report_Name += FullDate + "_"
    elif "Name" == name:
        Report_Name += Name + "_"
    elif "ElementID" == name:
        Report_Name += ElementID + "_"
    elif "ElementCD" == name:
        Report_Name += ElementCD + "_"
    elif "Year" == name:
        Report_Name += Year + "_"
    elif "Day" == name:
        Report_Name += Day + "_"
    elif "Month" == name:
        Report_Name += Month + "_"

You should also learn how to use format strings and the ** operator. If you change your FullDate stuff to a dictionary then you can use:

REPORT_FORMAT = '{FullDate}_{Month}_{Day}_{Year}_{ElementID}_{ElementCD}'

report = {
    'FullDate': now().format("yyyy-MM-dd_HH:mm:ss")
    'Name': "John"
    'ElementID': "Apple"
    'ElementCD': "01Appxz"
    'Year': now().format("yyyy")
    'Day': now().format("dd")
    'Month': now().format("MM")
}
report_name = REPORT_FORMAT.format(**report)
Peilonrayz
  • 3,129
  • 1
  • 25
  • 37
-1

Before reading:
- This is a solution that, as you mentionned, don't use dictionary


Solution

With:

#Default values
FullDate = '2010-01-01_00:00:00'
Name = "John"
ElementID = "Apple"
ElementCD = "01Appxz"
Year = '2010'
Day = '01'
Month = '01'
#--

String = "{FullDate}_{Month}_{Day}_{Year}_{ElementID}_{ElementCD}"

You can do this without for loop, just replacing as required:

Report_Name = '.RName_' + String
if "FullDate" in Report_Name:
    Report_Name = Report_Name.replace('{FullDate}',FullDate)
if "Name" in Report_Name:
    Report_Name = Report_Name.replace('{Name}',Name)
#...
if "ElementCD" in Report_Name:
    Report_Name = Report_Name.replace('{ElementCD}',ElementCD)

print(Report_Name)
.RName_2010-01-01_00:00:00_..._01Appxz

[Be carefull] Another solution

Or maybe you can use .eval() (see documentation) to evaluate variable from its name. It requires that parameters and variables name are the same.
Here is a way to do this:

import re
Parameters = [re.sub('[{-}]+', '', s) for s in String.split('_')]

Report_Name = '.RName_' + String
for p in Parameters:
    Report_Name = Report_Name.replace('{%s}'%p,eval(p))

print(Report_Name)
.RName_2010-01-01_00:00:00_01_01_2010_Apple_01Appxz

Be aware that you should use .eval() carefully - see Why is using eval a bad practice
Check alternatives to this solution - using globals/locals/vars for instance - if :

  • You want a similar behaviour
  • You think it is not safe enough for your problem
David Leon
  • 1,017
  • 8
  • 25