In the For loop below
def __str__(self):
output = " "
for i in range(len(self)):
output += (self.str_data[i] +" ")
return output
How may I rewrite this without using range & len or any other inbuilt function?
PS: str_data was used as instance variable of type list in init earlier.
If you're allowed to use join() then you could do:
def __str__(self):
return " ".join(self.str_data)
This is of course assuming len(self) would result in the same as len(self.str_data).
To result in exactly the same as your loop it would actually have to be:
def __str__(self):
if self.str_data:
return " " + " ".join(self.str_data) + " "
else:
return " "
New Answer: (no builtin functions)
def __str__(self):
output=""
for i in self.str_data:
output+=i+" "
return output
Old Answer :
asterisk and double asterisk can be used within list, tuple, set and dictionary, * will unpack list/tuple and ** will unpack dictionary.
my_array = [0,1,2,3,4,5]
print(*my_array) # unpacking list
Another method using join:
print(' '.join(map(str,my_array)))
Output
0 1 2 3 4 5
For the given question:
Since return keyword returns only one argument we can't unpack the list and we have to use function
def __str__(self):
return ' '.join(self.str_data)
You mean like this ?
class A(object):
def __init__(self, str_data):
self.str_data = str_data
def __str__(self):
return " ".join(str(s) for s in self)
def __iter__(self):
return iter(self.str_data)
if __name__ == '__main__':
print(A(["1", "2", "3", "4", "5"]))
import json
def __str__(self):
output = json.dumps(self.str_data)
output = output[1:-1].replace(',', ' ')
return output
For your consideration.
The previous answer is perfectly fine (if you omit builtins), but here's a closer version to what you did:
output = ""
array = [0,1,2,3,4,5]
for i in array:
output += "%s " % (i)
output = output[:-1]
return output
Please note that I change the way you set your output, as I think in order to get the result you want. Like you asked it does not use any builtin and it works just fine.
You could use highlevel functions like
" ".join(map(lambda x:x+" ",self.str_data))
map applies the function to add a space to each string in self.str_data and " ".join adds each of those to the starting string.
But of course these are built-in functions, it's just a really clean solution.
Alternitive to len() could be for loop - like:
var1 = 0
for var2 in list1:
var1 += 1
Related
I have multiple function that instead of returning they print a certain string I can’t put the whole function but that’s what they end up doing I want to take all of these function and make them into a single string.
Here’s an example of what one function would print and what I tried
def print_names(lst):
print(name)
def print_id(lst):
print(id)
lst = [name, not_name, not_name,id]
print_id(lst) + print_name(lst)
Doing this I get the error unsupported operand types for +: none type
You are getting this error because you are trying to add together the returned value for your print_names and print_id methods.
Since there is no return statement in these methods, the return value will be None and you cannot apply the + operator to the none type.
If you want to print these two items in your list together as one string, you would need to return the items, add them together, and print that:
lst = ['name', 'not_name', 'not_name','id']
def get_name(lst):
return lst[0]
def get_id(lst):
return lst[3]
print get_id(lst) + get_name(lst)
ok you should do it like this
def print_names(lst):
return lst[0]
def print_id(lst):
return lst[3]
lst = [name, not_name, not_name,id]
id_and_name = print_names(lst) + print_id(lst)
after that you will be able to print the "id_and_name" together
If you tried to return the Values, it would make it easier
def print_names(lst):
#rest of the function
return name
def print_id(lst):
#rest of the function
return id
lst = [name, not_name, not_name,id]
print(print_id(lst) + print_names(lst))
Functions return None, unless stated otherwise. print_id and print_name are returning both returning None and you are trying to add None + None which is not possible.
You can just return strings, concatenate (join) the two strings, and print that new string:
def get_name(lst):
return str(lst[0])
def get_id(lst):
return str(lst[3])
print(get_name(lst) + " " + get_id(lst))
or f-strings:
print(f"{get_name(lst)} {get_id(lst)}")
Or, use a dictionary so you dont need to index the data:
user_data = {
"name": "tom"
"id": 123456
}
print(f"{user_data["name"]} {user_data["id"]}")
The aim is to return the middle letter of a string, or " " if the string's even. I'm failing to see why my code doesn't work. Any sort of clarification would be great, thanks!
def mid(ml):
x=len(ml)
y=x+1
z=y/2
if isinstance(z,int)==True:
return (ml[z-1])
else:
return (" ")
print (mid("abc"))
/ doesn't return an int; even if the number it returns can be represented as one:
>>> 4 / 2
2.0 # A float
It would be better to explicitly check if the number is even or not:
# Read as: "If z is odd", or, "If division of z by 2 has a remainder of 1"
if z % 2 == 1:
return ml[z-1]
else:
return " "
This behavior occurs, because the / operator returns a float. Although the smarter way to solve this would be the use of the modulo operator, if you want to stick to your code, could use the is_integer() method of float like this:
def mid(ml):
x=len(ml)
y=x+1
z=y/2
if z.is_integer():
return (ml[int(z)-1])
else:
return (" ")
print (mid("abc"))
Better way to do it:
def mid(ml):
return ml[len(ml)//2] if len(ml) % 2 else ""
Following the answer from #Carcigenicate above you can try following code:
def mid(ml):
x=len(ml)
y=x+1
z=y/2
return (ml[int(z-1)])
print (mid("abc"))
I'm learning data and algorithm, here is the question I met
Question:Write a short recursive Python function that takes a character string s and
outputs its reverse. For example, the reverse of pots&pans would be
snap&stop .
a="pots&pans"
b=a.split("&")
c=[]
c=list(b)
def reverse(data,leng,leng2,index,count):
rev=(leng-1)-count
if count<leng/2:
temp=data[index][count]
data[index][count]=data[index][rev]
data[index][rev]=temp
if index==leng2:
print(data[index-1]+"&"+data[index])
return reverse(data,leng,leng2,index+1,count)
reverse(c,4,2,0,0)
I got an error here
TypeError: 'str' object does not support item assignment
My initial thought is that str is immutable. So it is better to store it in an list and do the operations. However, it met some problem when I trying to assign str to a list. Any solution to this?
Try this:
a="pots&pans"
b=a.split("&")
def reverse(word):
if not word:
return ""
return reverse(word[1:]) + word[0]
result = reverse(b[1]) + "&" + reverse(b[0])
print(result)
If you want one recursion to also reverse all the words position:
a="pots&pans&hello&hi"
b=a.split("&")
def reverse(lis):
if not lis:
return ""
if type(lis) == list and len(lis) == 1:
return reverse(lis[0])
if type(lis) == str:
return reverse(lis[1:]) + lis[0]
if type(lis) == list:
return reverse(lis[1:]) + "&" + reverse(lis[0])
print(reverse(b))
One recursive approach would be to append the first character to the reverse of the rest of the string:
def rev(s): return rev(s[1:])+s[0] if s else ""
output:
rev("pots&pans")
'snap&stop'
You could also do this without indexing using parameter unpacking:
def rev(first,*rest): return rev(*rest)+first if rest else first
rev(*"pots&pans")
'snap&stop'
Try this:
a="pots&pans"
def reverse(a_string):
`letter_list = list(a_string)`
`letter_list.reverse()`
`return(''.join(letter_list))`
print(reverse(a))
I am trying to mutate any instances of " " to print -: so I started by making a function that simply prints a list within a list on new lines:
def print_board(b):
print("\n".join(map(lambda x:"".join(map(str, x)),b)))
ex:
>>> print_board([[1,2,3],[2,3,4,5],[2,3,4]]
123
2345
234
Then I tried to use this similar method to mutate each instance that " " was in the list to -:
def is_empty(b0):
if b0 == " ":
return "-"
else:
return b0
def empty_space(b):
list(map(lambda x: list(map(is_empty, x)), b))#empty_space just mutates b
def check(b):
_board = empty_space(b)
return print_board(_board) #check just prints the mutated list b
and I would of wanted check(b) to do this for example:
>>> check([[" ",3,4],[5,6,3],[" ", " ", " "]])
-34
563
---
But I'm getting an error. I don't mind using recursion instead of map and lambda but I don't want to use for loops in any of these functions.
The only solution I can think of that doesn't explicitly use a for-loop is to copy the new list to the reference you've got:
def empty_space(b):
b[:] = map(lambda x: list(map(is_empty, x)), b)
this in effect changes the reference b passed to empty_space to have the values produced by the mapper, the list call is additionally not required since the right hand side can be any iterable.
You should also change check to be:
def check(b):
empty_space(b)
print_board(b)
since you aren't getting back any values.
Now this executes as required:
>>> check([[" ",3,4],[5,6,3],[" ", " ", " "]])
-34
563
---
b[:] does loop in the end (it must), I'm not really seeing why you feel the need to exclude for loops but I guess you must have your reasons.
You don't need recursion if you only work with 2D lists. I know you wrote you don't want to use any for loop, but map is nothing more than a disguised for loop. It also doesn't mutate the list.
So all you need is :
def check(rows):
for row in rows:
print "".join([str(x) for x in row]).replace(' ','-')
check([[" ",3,4],[5,6,3],[" ", " ", " "]])
# -34
# 563
# ---
If you really want to use maps :
def replace_char(char):
return str(char).replace(' ', '-')
def replace_row(row):
return "".join(map(replace_char, row))
def check(rows):
print "\n".join(map(replace_row, rows))
check([[" ",3,4],[5,6,3],[" ", " ", " "]])
# -34
# 563
# ---
def __number():
# This line returns the number of the latest created object
# as a "Factura" object in format "n/year"
last = Factura.objects.filter(f_type__exact=False).latest('number')
# We convert it into a string and split it to get only the first number
spl = str(last).split('/')[0]
# Convert it into integer so we can do math
n = int(spl)
# Get the current year
y = date.today().strftime('%y')
# If none return 1/year
if n == None:
return str(1) + '/' + str(y)
# Else we increment the number in one.
else:
n = n + 1
return str(n) + '/' + str(y)
What it does: It autogenerates a number in the format '1/year' '2/year' etc. If the user introduces other number, p.e. 564/10 the function follows it and the next will be 565/10.
Even if the user introduces p.e. 34/10 after the entry with 564/10 the function will follow the largest number.
Did I do this right or there's a better way to do it?
Update:
def __number():
current_year = date.today().strftime('%y')
try:
facturas_emmited = Factura.objects.filter(f_type__exact=False)
latest_object = facturas_emmited.latest('number').__str__()
first_number = int(latest_object.split("/")[0]) + 1
except Factura.DoesNotExist:
first_number = 1
return '%s/%s' % (first_number, current_year)
This is really just the beginning, but I'd start by replacing some comments with self-documenting code.
def __number():
# "Factura" object in format "n/year"
latest_object = Factura.objects.filter(f_type__exact=False).latest('number')
# Better name can be available if you explain why the first number is important and what it means
# Do Factura objects not have a __repr__ or __str__ method that you must cast it?
first_number = int(str(latest_object).split('/')[0])
current_year = date.today().strftime('%y')
# Use "is None" rather than "== None"
if first_number is None:
return '1/%d' % current_year
# No else needed because of return above
# Why do we add 1 to first number? Comments should explain _why_, not how
return '%d/%d' % (first_number + 1, current_year)
Can last be None? If so it would be good to check for that:
# get last as before
if last:
n = int(str(last).split("/")[0]) + 1
else:
n = 1
# get y as before
return str(n) + "/" + str(y)
Another improvement here is that you only build the result string in one place.
I don't know what the Factura object is, but can you not get the value of n by calling some method on it? This would be better than converting it to a string, splitting it and taking the last part.
I solved similar problem some time ago by using object.id/year (where object/id is database id).
It guarantees that this will be unique, autoincremented (you don't need to do n = n + 1, which theoretically can lead to duplicate values in a db).
You can do this by overriding save method and only trick is that you need first to save an object (id is assigned) and then create id/year number and save again (maybe there is better way to do this than double save).
def save(self, force_insert = False, force_update = False):
super(Factura, self).save(force_insert, force_update)
current_year = date.today().strftime('%y')
self.identifier = '%s/%s'%(self.id, current_year)
super(Factura, self).save(force_insert, force_update)