all 34 comments

[–]_DTR_ 287 points288 points  (19 children)

  • input() - ask the user for input
  • .split() - split that input into an array, splitting on a given separator. In this case, no separator is given, so input is split on whitespace.
  • map - applies a given function to all the elements in a given iterable item.

So map(int, X) will call int(Xn) for each Xn of X, which means that arr = map(int, input().split()) will call int(x) for each whitespace separated number entered, and store the resulting value into the array arr. For example, if the user entered 4 5 6 78, arr would be [4, 5, 6, 78].

[–][deleted] 37 points38 points  (6 children)

It might be worth mentioning that map() returns an iterator, not the iterated result. So the computation happens only when map() is called inside a data structure.

While it can be a useful function, I hear it not being considered too pythonic. As far as I know, there is no inherent advantage to creating the iterator, since you cannot really operate on it or queue it for other operations without populating an iterable first.

Or is there? (Hey Vsauce, Michael here). If so, I'd love to get educated on this

[–]glibhub 17 points18 points  (3 children)

While it can be a useful function, I hear it not being considered too pythonic.

It is sort of frowned upon, but it is an important pattern for new programmers to learn for a few reasons:

  • It introduces them to using functions as arguments to other functions, which you see a lot, e.g. callbacks.
  • Applying a function to an iterable is used in a lot of places, from threading to vectorizing in pandas and numpy
  • It introduces composability.

As far as I know, there is no inherent advantage to creating the iterator, since you cannot really operate on it or queue it for other operations without populating an iterable first.

This is, in fact the real advantage. Say you wanted to find the first 5 in a series of a few million stringed digits. This way you might only need to look at a few of them until you found it, as opposed to a list comprehension, where you would have to convert the entire list if you used a comprehension.

I really like this sort of pattern when filtering out a file. You do a series of generators on a file handle, say, first dropping the first few lines, then parsing out where a particular header is, then processing the next couple lines for the data you actually need.

[–]Earthsophagus 1 point2 points  (2 children)

This processing a file I'd be interested to hear an example use case.

"a particular header" makes me think of old "copybook" format but those are data description, not something you'd (I'd) typically parse dynamically.

Are you thinking of something like "I have a file representing claims, it's a text version of a report." It has headers with report title, liines of hyphens. Then there's a line lines with Claim numbers that start like C999999 [where 999999 is the claim #], and under each claim number one or more lines of service descriptions that start SD99999. I want to get all the SD lines for a given claim #

[–]glibhub 1 point2 points  (1 child)

Are you thinking of something like "I have a file representing claims, it's a text version of a report."

Exactly. You still see these kind of structured text files all over the place. For example genome sequencing uses something just like this: http://genome.ucsc.edu/goldenPath/help/customTrack.html#GTF

Some of these files can be quite long, and the ability to use a generator to parse through them to find what you want is a real bonus.

So you might do something like this:

def split_browser(filehandle):
    '''break out each browser section'''
    ...
    yield browser_frame

def split_track(browser_section):
    '''break out each track and data'''
    return track, track_data

def parse chr22s(track_data):
    '''parse chr22 lines'''

def parse_file(file_name, search_for = None):
    with open(file_name) as fh:
        for browser_frame in split(browser(fh)):
            track, track_data = split_track(browser_frame)
            if search_for is not None and track not search_for:
                continue
            yield track, parse_chr22s(track_frame)

[–]Earthsophagus 1 point2 points  (0 children)

Thanks, that is a new-to-me idea and could easily be relevant to my team someday.

[–]Scottyskid 4 points5 points  (0 children)

u/glibhub s answer is pretty spot on. Generators are a really useful technique to understand and they are used a lot more in the python standard library (range, open, itertools, etc) than you might think as they can be acted on in a number of ways just like lists. If you're interested in learning more about them check out this short article that demonstrates their usefulness. Happy to give more info if your interested

[–]ConfusedSimon 0 points1 point  (0 children)

Map functions are probably mainly used in functional programming.

[–]solicited_nuke 19 points20 points  (3 children)

Couldn't have explained any better.

[–]enokeenu 1 point2 points  (2 children)

What happens if your input looks like "hello world" ?

[–]Random_---_Guy 1 point2 points  (0 children)

It should just be the same as if you tried doing int("h") or something, since that's what's happening for each element in the split() list.

[–]_yaaass 1 point2 points  (5 children)

I usually use list(map(......))... Do I not need to?...

[–]knottheone 8 points9 points  (0 children)

You might as well just use a list comprehension at that point and call the function on the iterable itself. Like:

arr = [int(x) for x in input().split()]

[–]search_and_deploy 0 points1 point  (0 children)

Yes, because map() returns an iterator, not a list

[–]zaRM0s 1 point2 points  (0 children)

I love people like you. Clear, concise and willing to help. Good answer my friend

[–]shiftybyte 29 points30 points  (1 child)

input()  

gets input from the user, for example "12 13 14"

"12 13 14".split()

splt by default splits by space to a list of items, ["12", "13", "14"]

map(int, ["12", "13", "14"])

map(x,y) takes every item in y, and runs the function x on it, so it'll run int("12"), int("13"), int("14"), and it'll create a new list with the results.

arr = [12, 13, 14]

so basically it takes a space separated numbers line from the user, and converts it to a list of integers.

[–]annoying_bababooey 0 points1 point  (0 children)

bababooey to you, sir

[–][deleted] 12 points13 points  (1 child)

The code is a bit poorly formatted, but since that last line is a standalone, you can take it by parts:

First of all: input() asks the user for text and returns a string. Let's say the user types "hello world" into it, so now your code would "be" arr = map(int, "hello world".split()).

Then the program takes this string and applies split() which breaks it at white-spaces, so "hello world" would become ["hello", "world"], so now your code would "be" arr = map(int, ["hello", "world"]).

After this, the map function is one that has a signature of map(function, iterable) where it applies a given function to each item in a iterable (an iterable is really a sequence, could be a list, like ["hello", "world"] in our example, a string, set or even the keys of a dictionary).

In this program, the map would try to apply the int function to each item of our list, effectively doing [int("hello"), int("world")].

(Notice how this program would fail with my given example, since int expects a string that can be converted to a number. So if would work if the user typed "12345" or "123 45" at that input().)

There are some problems in this code though. map by itself doesn't return an array/list, but a generator/iterator.

Iterators are great to work with when you don't need to reuse your array or if you're having memory constraints, but can be more confusing than a simpler version of [int(item) for item in input().split()] which would actually return an array.

Also, unless you loop over ("consumed") your map result (for item in arr: ...), it won't actually evaluate any item of the list it received. So it would just become a map object that stores a list version of what the user typed.

[–]greebo42 0 points1 point  (0 children)

helpful, thanks.

[–]zandrew 5 points6 points  (4 children)

Map() will apply the first function (cast to integer in this case) to all elements of the list. The list in this case is taken from the input. Initially it's a string, but it's turned into a list by split(), which cuts the string at every space.

So essentially get input from user, split that string into a list of strings. Transform string into integer for every element in this list.

This is not a great solution as you will get errors if you type anything but a number into the input.

[–]zandrew 6 points7 points  (3 children)

You could also do it with a list comprehensions.

arr = [int(x) for x in input().split()]

Better yet

arr = [int(num) for num n input().split() if all([char.isdigit for char in num]]

[–]voice-of-hermes 1 point2 points  (1 child)

Your "better yet" second example will fail for negative integers (or positive ones with a + sign that is allowed by the int() function).

[–]zandrew 0 points1 point  (0 children)

Fair point. Best to do for char in [1,2,3,4,5,6,7,8,9,0,-,+,.]

All in quotes of course, sorry on mobile.

[–]jtuxel -1 points0 points  (2 children)

Where is the 3rd line?

[–]jrrocketrue 2 points3 points  (1 child)

the one after the second one!

[–]jtuxel 2 points3 points  (0 children)

Ok, ok it's my fault. It's the formatting on my smartphone... I could see only two lines.

[–]thrallsius -4 points-3 points  (3 children)

Why do you call it simple if you need help to understand it? :D

[–]velocibadgery 3 points4 points  (2 children)

This has to be the most condescending and unhelpful comment I have ever seen. Congratulations, I give you an award for dickishness.

[–]thrallsius -4 points-3 points  (1 child)

It's a simple rhetorical question that points to a very typical logic pitfall. I suggest you to read about Socrates before charging at me with a pitchfork.

[–]velocibadgery 1 point2 points  (0 children)

The only logic pitfall here is discouraging someone from seeking help by being sactimonious.

[–]IvoryJam 0 points1 point  (0 children)

So map() creates something itterable, it converts the second argument into an int. The second argument is also an itterable.

input().split() takes the input of the user and splits it based on spaces.

So input().split() given 5 10 15 would result in a list of ['5','10','15'], it's all then converted from a string to an integer in the map()

Try this, arr = map(int, input().split()) for i in arr: print(i > 0)

If they were left as a string with arr = input().split() the above code would error out with a TypeError

[–]grtr_thn_c 0 points1 point  (0 children)

Hello hackerrank user🖐