Iteration loop for the large number of variable naming - python

I want to generate a number of note in a music database, but I don't know how to use some iteration like for loop to simplify the following, I hope someone can shed some lights on me.
note1 = note.Note(tune_array_bass[0])
note2 =note.Note(tune_array_bass[1])
note3 =note.Note(tune_array_bass[2])
note4 =note.Note(tune_array_bass[3])
note5 =note.Note(tune_array_bass[4])
note6 =note.Note(tune_array_bass[5])
note7 =note.Note(tune_array_bass[6])
note8 =note.Note(tune_array_bass[7])
note9 =note.Note(tune_array_bass[8])
note10 =note.Note(tune_array_bass[9])
note11 =note.Note(tune_array_bass[10])
note12 =note.Note(tune_array_bass[11])
note13 =note.Note(tune_array_bass[12])
note14 =note.Note(tune_array_bass[13])

I didn't exactly understand what you meant but, here's my solution to list the notes using a loop:
class Note:
def __init__(self,note):
self.note = note
tune_array_bass = [1,2,3,4,5,6,7,8,9,10,11,12,13]
for item in tune_array_bass:
new_notes = Note(item)
print(new_notes)

You could store the objects in a list instead:
notes = []
for i in range(14):
notes.append(note.Note(tune_array_bass[i]))
Then you can access each note object using notes[0], notes[1] etc.

Don't create many individual variables like this.
Instead, you could use a list:
notes = [note.Note(tune_array_bass[i]) for i in range(14)]
# get a note from the list:
notes[0]
Or a dictionary:
notes = {f"Note{i+1}":note.Note(tune_array_bass[i]) for i in range(14)}
# get a note from the dict:
notes["Note1"]

Related

Ren'py / Python - insert dynamic variable in class with a while loop - without overwriting with append

I'm currently trying to get into Python and Ren'Py a bit. Since I like to design a lot dynamically
and don't want to use copy&paste so often, I'm trying to create a page that will have ImageButtons with the corresponding number I specify.
In the example below I use "4" - but this can be higher.
I have built a class for this purpose:
Example:
init python:
class PictureSettings(object):
def __init__ (self, ImgIdle, ImgHover, LabelCall):
self.ImgIdle = ImgIdle
self.ImgHover = ImgHover
self.LabelCall = LabelCall
return
For the Idle/Hover and for the Jump.
If I insert in the code now in an object each entry "manually" with append I get all 4 pictures as desired indicated.
Example: (Works - but is not dynamic)
python:
var_pictures = []
var_pictures.append(PictureSettings("img_picture_1_idle", "img_picture_1_hover", "picture_1"))
var_pictures.append(PictureSettings("img_picture_2_idle", "img_picture_2_hover", "picture_2"))
var_pictures.append(PictureSettings("img_picture_3_idle", "img_picture_3_hover", "picture_3"))
var_pictures.append(PictureSettings("img_picture_4_idle", "img_picture_4_hover", "picture_4"))
I would like it to be like this:
Example (Here I get only ""img_picture_4_idle", "img_picture_4_hover", "picture_4""):
$ countlimit = 4
$ count = 1
python:
while count < countlimit:
var_pictures = []
var_pictures.append(PictureSettings(
ImgIdle = "img_picture_[count]_idle",
ImgHover = "img_picture_[count]_hover",
LabelCall = "picture_[count]"))
count += 1
Have already tried various things, unfortunately without success.
For example: with Add - instead of append (because this overwrites the result and leaves only the last entry
I get the following error:
var_pictures.add(PictureSettings( AttributeError: 'RevertableList' object has no attribute 'add')
Maybe someone can help me with the solution so I can keep my code dynamic without copying something X times.
Thanks for your help
You are creating your list inside your loop, so it is recreated every time.
At the end, you only get the last created list.
var_pictures = []
while count < countlimit:
var_pictures.append(PictureSettings(
ImgIdle = "img_picture_[count]_idle",
ImgHover = "img_picture_[count]_hover",
LabelCall = "picture_[count]"))
count += 1
On another subject, if you want to do this in a more pythonic way:
pictures = [] # no need for var_, we know its a variable
for i in range(1, 5):
pictures.append(PictureSettings(
# in python, we prefere snake_case attributes
img_idle=f'img_picture_{i}_idle',
img_hover=f'img_picture_{i}_hover',
...
))
# or even shorter with list comprehension
pictures = [
PictureSettings(
img_idle=f'img_picture_{i}_idle',
)
for i in range(1, 5)
]
By the way, no need to return in your class constructor

How to traverse dictionary keys in sorted order

I am reading a cfg file, and receive a dictionary for each section. So, for example:
Config-File:
[General]
parameter1="Param1"
parameter2="Param2"
[FileList]
file001="file1.txt"
file002="file2.txt" ......
I have the FileList section stored in a dictionary called section. In this example, I can access "file1.txt" as test = section["file001"], so test == "file1.txt". To access every file of FileList one after the other, I could try the following:
for i in range(1, (number_of_files + 1)):
access_key = str("file_00" + str(i))
print(section[access_key])
This is my current solution, but I don't like it at all. First of all, it looks kind of messy in python, but I will also face problems when more than 9 files are listed in the config.
I could also do it like:
for i in range(1, (number_of_files + 1)):
if (i <= 9):
access_key = str("file_00" + str(i))
elif (i > 9 and i < 100):
access_key = str("file_0" + str(i))
print(section[access_key])
But I don't want to start with that because it becomes even worse. So my question is: What would be a proper and relatively clean way to go through all the file names in order? I definitely need the loop because I need to perform some actions with every file.
Use zero padding to generate the file number (for e.g. see this SO question answer: https://stackoverflow.com/a/339013/3775361). That way you don’t have to write the logic of moving through digit rollover yourself—you can use built-in Python functionality to do it for you. If you’re using Python 3 I’d also recommend you try out f-strings (one of the suggested solutions at the link above). They’re awesome!
If we can assume the file number has three digits, then you can do the followings to achieve zero padding. All of the below returns "015".
i = 15
str(i).zfill(3)
# or
"%03d" % i
# or
"{:0>3}".format(i)
# or
f"{i:0>3}"
Start by looking at the keys you actually have instead of guessing what they might be. You need to filter out the ones that match your pattern, and sort according to the numerical portion.
keys = [key for key in section.keys() if key.startswith('file') and key[4:].isdigit()]
You can add additional conditions, like len(key) > 4, or drop the conditions entirely. You might also consider learning regular expressions to make the checking more elegant.
To sort the names without having to account for padding, you can do something like
keys = sorted(keys, key=lambda s: int(s[4:]))
You can also try a library like natsort, which will handle the custom sort key much more generally.
Now you can iterate over the keys and do whatever you want:
for key in sorted((k for k in section if k.startswith('file') and k[4:].isdigit()), key=lambda s: int(s[4:])):
print(section[key])
Here is what a solution equipt with re and natsort might look like:
import re
from natsort import natsorted
pattern = re.compile(r'file\d+')
for key in natsorted(k for k in section if pattern.fullmatch(k)):
print(section[key])

Create dictionaries from data frames stored in a dictionary in Python

I have a for loop that cycles through and creates 3 data frames and stores them in a dictionary. From each of these data frames, I would like to be able to create another dictionary, but I cant figure out how to do this.
Here is the repetitive code without the loop:
Trad = allreports2[allreports2['Trad'].notna()]
Alti = allreports2[allreports2['Alti'].notna()]
Alto = allreports2[allreports2['Alto'].notna()]
Trad_dict = dict(zip(Trad.State, Trad.Position))
Alti_dict = dict(zip(Alti.State, Alti.Position))
Alto_dict = dict(zip(Alto.State, Alto.Position))
As stated earlier, I understand how to make the 3 dataframes by storing them in a dictionary and I understand what needs to go on the right side of the equal sign in the second statement in the for loop, but not what goes on the left side (denoted below as XXXXXXXXX).
Routes = ['Trad', 'Alti', 'Alto']
dfd = {}
for route in Routes:
dfd[route] = allreports2[allreports2[route].notna()]
XXXXXXXXX = dict(zip(dfd[route].State, dfd[route].Position))
(Please note: I am very new to Python and teaching myself so apologies in advance!)
This compromises readability, but this should work.
Routes = ['Trad', 'Alti', 'Alto']
dfd, output = [{},{}] # Unpack List
for route in Routes:
dfd[route] = allreports2[allreprots2[route].notna()]
output[route] = dict(zip(dfd[route].State, dfd[route].Position))
Trad_dict, Alti_dict, Alto_dict = list(output.values()) # Unpack List
Reference
How can I get list of values from dict?

Get just the very next list within a nested list in python

How do you get the very next list within a nested list in python?
I have a few lists:
charLimit = [101100,114502,124602]
conditionalNextQ = [101101, 101200, 114503, 114504, 124603, 124604]`
response = [[100100,4]
,[100300,99]
,[1100500,6]
,[1100501,04]
,[100700,12]
,[100800,67]
,[100100,64]
,[100300,26]
,[100500,2]
,[100501,035]
,[100700,9]
,[100800,8]
,[101100,"hello"]
,[101101,"twenty"] ... ]
for question in charLimit:
for limitQuestion in response:
limitNumber = limitQuestion[0]
if question == limitNumber:
print(limitQuestion)
The above code is doing what I want, i.e. printing the list instances in response when it contains one of the numbers in charlimit. However, I also want it to print the immediate next value in response also.
For example the second-to-last value in response contains 101100 (a value thats in charlimit) so I want it to not only print
101100,"hello"
(as the code does at the moment)
but the very next list also (and only the next)
101100,"hello"
101101,"twenty"
Thank is advance for any help here. Please note that response is a verrrrry long list and so I'm looking to make things fairly efficient if possible, although its not crucial in the context of this work. I'm probably missing something very simple but cant find examples of anyone doing this without using specific indexes in very small lists.
You can use enumerate
Ex:
charLimit = [101100,114502,124602]
conditionalNextQ = [101101, 101200, 114503, 114504, 124603, 124604]
response = [[100100,4]
,[100300,99]
,[1100500,6]
,[1100501,04]
,[100700,12]
,[100800,67]
,[100100,64]
,[100300,26]
,[100500,2]
,[100501,035]
,[100700,9]
,[100800,8]
,[101100,"hello"]
,[101101,"twenty"]]
l = len(response) - 1
for question in charLimit:
for i, limitQuestion in enumerate(response):
limitNumber = limitQuestion[0]
if question == limitNumber:
print(limitQuestion)
if (i+1) <= l:
print(response[i+1])
Output:
[101100, 'hello']
[101101, 'twenty']
I would eliminate the loop over charLimit and loop over response instead. Using enumerate in this loop allows us to access the next element by index, in the case that we want to print it:
for i, limitQuestion in enumerate(response, 1):
limitNumber = limitQuestion[0]
# use the `in` operator to check if `limitNumber` equals any
# of the numbers in `charLimit`
if limitNumber in charLimit:
print(limitQuestion)
# if this isn't the last element in the list, also
# print the next one
if i < len(response):
print(response[i])
If charLimit is very long, you should consider defining it as a set instead, because sets have faster membership tests than lists:
charLimit = {101100,114502,124602}

How to write a function in python?

I am doing exploratory data analysis, while doing that i am using the same lines of code many times .So i came to know that why can't i wrote the function for that.But i am new to python i don't know how to define a function exactly.So please help me.....
textdata is my main dataframe and tonumber,smstext are my variables
# subsetting the textdata
mesbytonum = textdata[['tonumber', 'smstext']]
# calculating the no.of messages by tonumber
messbytonum_freq = mesbytonum.groupby('tonumber').agg(len)
# resetting the index
messbytonum_freq.reset_index(inplace=True)
# making them in a descending order
messbytonum_freq_result = messbytonum_freq.sort(['smstext'], ascending=[0])
#calcuating percentages
messbytonum_freq_result['percentage'] = messbytonum_freq_result['smstext']/sum(messbytonum_freq_result['smstext'])
# considering top10
top10tonum = messbytonum_freq_result.head(10)
# top10tonum
i have repeated the similar kind of code around 20 times so i want to write the function for the above code which makes my code smaller. So please help me how can i define.
Thanks in advance
The function is defined like this:
def func(arg1, arg2, argN):
# do something
# you may need to return value(s) too
And called like this:
func(1,2,3) # you can use anything instead of 1,2 and 3
It will be
def MyFunc(textdata):
mesbytonum = textdata[['tonumber', 'smstext']]
messbytonum_freq = mesbytonum.groupby('tonumber').agg(len)
messbytonum_freq.reset_index(inplace=True)
messbytonum_freq_result = messbytonum_freq.sort(['smstext'], ascending=[0])
messbytonum_freq_result['percentage'] = messbytonum_freq_result['smstext']/sum(messbytonum_freq_result['smstext'])
top10tonum = messbytonum_freq_result.head(10)
return # what do you want to return?
# use this function
result=MyFunc(<argument here>)
# then you need to use result somehow
Your function can also return multiple values
return spam, egg
which you have to use like this
mySpam, myEgg=MyFunction(<argument>)

Categories