5 ms·
Sadly, no. It's like I asked for a tuna sandwich and you explained how to build the engine of the fishing boat to go catch the tuna off the coast of Baja. I f
by chris_mahan 12y ago
Sadly, no.
It's like I asked for a tuna sandwich and you explained how to build the engine of the fishing boat to go catch the tuna off the coast of Baja.
I feel like I need a masters in computer science to understand what you wrote.
let me see:
# Python:
domains = []
emails = open("file_with_emails.txt","r").readlines()
for email in emails:
____domain = email.split("@")[1]
____if domain not in domains:
________domains.append(domain)
out = open("file_with_domains.txt","w")
for domain in domains:
____out.write(domain)
out.close()
input:
joe@msn.com
mike@aol.com
tim@aol.com
sam@hotmail.com
output:
msn.com
aol.com
hotmail.com
Simple no?
- innguest 12y agoThat's actually not simple at all because it assumes an implementation, that is, a machine with RAM that changes. For instance, what does = mean between domain and email.split ? Who is equal to who? That question is a question that students sometimes have. You have to explain that Time is implicit in the code, and that an equal sign works by making the thing on the left equal to what the thing on the right was just before this line. So now there's a concept of Time and that's how things start to get very complicated, because it is implicit in your code. Then, what does ".append" mean? I mean, you call append, but now you don't assign the result to any variable? And what would it mean if you said domains = domains.append(domain), then we really need to have a talk about the hidden Time. So it only seems simple because it's familiar to you; so in fact I believe it's not simple at all. But this I believe it's simple, and my fishing boat engine above would've benefited from this: https://www.fpcomplete.com/tutorial-preview/4217/4k7kq6jGUE https://www.fpcomplete.com/tutorial-preview/4217/4k7kq6jGUE If you look at that code (you can also click play to run it) and then look at the explanation again, could you please tell me what doesn't seem simple? Edit: let's not forget your Python example uses a map, disguised as a for loop. That for is a keyword, but backstage it's just map where email is the element, emails is the list, and everything you write inside that scope is the function that gets passed the element each time (except in your case the function (i.e. the loop body) can also see the whole list, which is prone to bugs).
- chris_mahan 12y agoThanks. I looked at the code you provided. it makes still very little sense to me. You're right though that my using python language features like lists and file open and loops is like function, but I understand those, so I can use them.
- chris_mahan 12y agoAlso, a machine with RAM that changes. Well, yes, and files that change too. I'm completely ok with that.
- chris_mahan 12y ago"Edit: let's not forget your Python example uses a map, disguised as a for loop" Mmmm, really? A map? Like Google maps? Like a paper map? unfamiliar terminology. Seriously, I learned how to use for loops in 1984. Been using them ever since. Maybe that's the problem. Too old to learn new tricks.
- innguest 12y agoIt's not unfamiliar, you got it right, the map I'm talking about is exactly like that maps you described, in that they both contain directions (all the possible origin-destination relationships between all the places) and you can draw arrows from one place to another (thereby defining a "route" that represents the act of starting to walk from point A and arriving at point B). If you cared to learn you would benefit a lot from it. Oh, but the moral of the story is that because the computer understands those maps, then I can simply tell it what I have (point A, origin) and what I want (point B, destination) without telling it how to do it. Then the computer goes and writes that code for me! The same code you're now still writing manually. Because you don't want to learn a new "trick". :)
- chris_mahan 12y agoThat still made no sense, sorry.
- dragonwriter 12y ago
- voyou 12y agoI think the main difficulty in converting your example to a functional style is how to express the idea of a for loop which builds up a result as it goes along, without using a mutable variable to store this result. Here's an attempt to explain how that the ideas in the parent are helpful in solving that problem. You can think of the body of a for loop in python as the body of a function. In that case, a for loop is like the built-in map function, which applies that function to every element of the list. So convert your for loop into: def body(email): domain = email.split("@")[1] if domain not in domains: domains.append(domain) And instead of a for loop we can use the standard function, 'map'. domains = [] map(body, emails) Now, obviously the data here isn't immutable. But what if, instead of changing 'domains' every time the function is called, we passed in the current value of 'domains', and returned a changed value, like so: def body(domains, email): domain = email.split("@")[1] if domain not in domains: return domains + [domain] else: return domains Then, we could apply this function to each element of the list in turn, passing the current list of domains at each stage to the body. This is the standard function 'reduce' in Python (which the parent calls by its other common name, 'fold'): domains = reduce(body, emails, []) You could think of 'reduce' in python being implemented like: def reduce(func, l, currentResult): for item in list: currentResult = func(currentResult, item) return currentResult Or, it could also be implemented recursively, which means it wouldn't need to use mutation internally: def reduce(func, l, currentValue): if len(l) == 0: return currentValue else: return reduce(func, l[1:], func(currentValue, l[0])) Many for loops that build up a result can be expressed instead using 'reduce', so reduce is one of the most important building blocks of functional programming.
- stevesimmons 12y agoExcept you'd never write it like that in idiomatic Python. Your reduce's repeated list copying/appending/searching kills performance. Instead you would do something like this: domains = set( email.split('@')[-1] for email in open(path) )
- innguest 12y agoHe's pretending python compiles to something sane. FP spoils you with great compilers.
- zohebv 12y agoHere is some scala code does the same thing FileIterator("input.txt").map{_.split('@').last}.distinct.toFile("output.txt") Lets compare it to the Python version. It looks much shorter, but many constructs are similar to what you wrote and it can be argued that the Scala code is merely a rearrangement of the tokens in the Python code. So let us explicitly call out the tokens/items I did not use in the Scala code, but you did in the Python code. domains = [] domains.append(domain) out.close() infile.close() // I think you missed closing the input file, a handle leak bug The map method encapsulates the construction of the output list and the FileIterator and toFile methods encapsulate the opening and closing of files. In particular, the Scala code hjas no handle leak bug. What functional languages are really good at is abstraction. map has abstracted away iteration and construction of an output list, while the file handling methods abstract away resource usage. As programs get bigger and more complex, this power of abstraction becomes increasingly powerful. (Note that FileIterator and toFile are constructs that I wrote for myself a long time ago, differing constructs are available in the Scala std lib)
- dragonwriter 12y agoIn functional style, but still in Python (given that python method calls are equivalent to function calls with an additional first argument of the receiver object, and indexing is equivalent to a method call) -- this uses mutable objects, but doesn't actually rely on mutating them: addEmail = lambda |doms,email| doms.union([email.split("@")[1]]) domains = reduce(set(),addEmail,open("file_with_emails.txt","r"))) open("file_with_domains.txt","w").writelines(domains) (Loses order because of use of set for deduplication; you could do it with a list and keep order, but then addEmail becomes more complex, and I don't think its strictly necessary to illustrate the general process. Also, its not clear to me that order-preservation is really part of the intended function here or just an artifact of the implementation. Note that this could be a one-liner, its just split up into three lines with two as assignments for readability.) And, more how I'd really write it in Python (which is also functional, though perhaps less obviously so, and leverages Python set comprehensions): domains = { email.split("@")[1] for email in open("file_with_emails.txt","r") } open("file_with_domains.txt","w").writelines(domains)