Transforming Every List Item

On this page, you will use the map block to create an initials from name block and then use map together with initials from name to find the initials of all of your contacts.

Alphie, Betsy, and Gamal are building an initials from name block that accepts one contact as input and reports that person's initials.
initials from name (name from contact( (item (1) of (contact list)) reporting 'BA'
Betsy: I used the split () by ('pink dot indicating a space character') block to break up the contact's full name into a list of their names, and then I joined the first letter of each name:
initials from contact: (contact) {
    script variables (list of names)
    set (list of names) to (split (name from contact (contact)) by (word))
    report (join (letter (1) of (item (1) of (list of names))) (letter (1) of (item (2) of (list of names))) )
}
What's the difference between splitting by spaces and splitting by words?

Try it! (Each brown dot represents a space.)
split "hello␠␠␠␠␠␠␠world" by (␠) split "hello␠␠␠␠␠␠␠world" by word

In one case, split is focusing on the exact characters in the string. In the other case, it's giving you what you really want: the words in the contact's name. At a low level of abstraction, text is made of characters and you look through each of the characters. But at a higher level of abstraction (such as when you are reading), text is made up of words. Snap! lets you think at this higher level of abstraction.

Alphie: But what about someone who goes by three names like Martin Luther King? It would just report "ML" for him.
Gamal: Oh, that's because the block only takes the first letter of items 1 and 2. We have to add in letter (1) of (item (3) of (list of names)).
Betsy: But what if someone has more names than that? In my aunt's family they each have five or six names...
Gamal: Well, then we need to take letter (1) of each item in the list of names. That sounds as if what we need is a higher-order function. Higher-order functions are good at doing things with individual items in a list.

A higher-order function is a function that takes a function as input (or reports a function as output).

  1. Build and experiment with these examples of the map function.
    map (join( )(s)) over (list{block, script, Boolean})
    map ((3) * ( )) over (list{7, 8, 1})
    map (letter (1) of ( )) over (list{bounce, join, clear})
  2. Talk with Your Partner Discuss and then explain in writing what these expressions are doing.

The map 'reporter input slot' over 'list input slot' block takes two inputs: a function (a reporter with a blank input slot) and a list, and it reports a new list in which each item is the result of calling the function with an item from the original list as input. For example:
map (join( )(s)) over (list {cat, dog, bird}) reporting {cats, dogs, birds}
map (round ( )) over (list{3.14159, 87, 5.4}) reporting {3, 87, 5}

You choose the function that describes the result for one input item, and map applies that function to each item in the input list and then reports the list of result values. If your function has item 1 of or item 2 of in it, you're probably trying to do map's part of the job. 

Map is a higher-order function just like keep and combine. The function mapped over the list always has a blank input slot. This is where the list item goes each time the function is performed.

This picture shows how the three higher-order functions could be used:
picture of map transforming each item, keep blocking some input items so they don't appear in the result, and combine superimposing them into one icon
See the higher-order function expressions with these (imaginary) shape procedures.

map (shade figure ()) over (list of figures) keep items (is () a polygon?) over (list of figures) combine (list of figures) using (overlay ())

Here is a quick review of the higher-order functions map, keep, combine.

  • Map performs a function on every item of a list and reports the list of changed items.
    map (( )-(1)) over (list (96) (-100) (4.7)) reporting
  • Keep uses a predicate function (a true/false question) to check every item in a list and reports the items that make the predicate true. (You learned about keep on Unit 2 Lab 3 Page 5: Keeping Items from a List.)
    keep-items-such-that-(last-letter-of-(input)-equals-h)-from-test-list
  • Combine uses a combining function (a function with two inputs) to report the results of combining all the items in a list using that function. (You learned about combine on Unit 2 Lab 4 Page 3: More Mathematical Reporters.)
    combine (list {0, 1, 2}) with (()+()) reporting 3

  1. If it isn't open already, open your U3L2-ContactList project.
  2. Use map and combine together to build an initials from name reporter that takes a name as input and reports that person's initials.
    initials from name (name from contact( (item (1) of (contact list)) reporting 'BA' initials from name (Martin Luther King) reporting 'MLK'
  3. Test and debug your initials from name block.
  4. Create an expression to report a list of the initials of all your contacts.
    Need a hint?

    First, create an expression to report a list of the names of all your contacts.
    contact list watcher in list view list in list view containing three items: Betsy Anderson, Alphie Preston, Gamal Abdel

    contact list watcher in list view list in list view containing three items: BA, AP, GA
  5. Which of the following statements are true about this list?
    set (words and numbers) to {rabbit, 5, benefit, is, 34, kite, 2, 305, the, 61}
    map (letter (1) of ()) over (words and numbers) reports the list {r, 5, b, i, 3, k, 2, 3, t, 6}.
    map (item (1) of ()) over (words and numbers) reports the list {rabbit}.
    Both of the above.
    None of the above.
  6. Which of the following statements are true about this list?
    set (capitals) to {{Augusta, Maine}, {Boise, Idaho}, {Columbia, South Carolina}, {Des Moines, Iowa}}
    Choose all that apply.
    Why not use an ADT?

    The list inside a list shown above makes it clearest to you now as you answer this self-check item what the structure is, but you're right, in an actual program it would be better to use an abstract data type:
    state: (Augusta) capital: (Maine)

    map (item (1) of ()) over (capitals) reports the list {Augusta, Boise, Columbia, Des Moines}.
    map (item (1) of ()) over (capitals) reports the list {Augusta, Maine}.
    map (letter (1) of ()) over (capitals) reports the list {A, B, C, D}.
    map (all but first of ()) over (capitals) reports the list {Maine, Idaho, South Carolina, Iowa}.
    map (all but first of ()) over (capitals) reports the list {{Boise, Idaho}, {Columbia, South Carolina}, {Des Moines, Iowa}}.
  7. Read the two scripts below; they do the same thing. Write Out Your Thoughts Give two reasons why the use of abstraction in the second example is preferred.
    script variables (names of contacts)
set (names of contacts) to (list)
for each (contact) of (contact list) {
	add (name from contact: (contact)) to (names of contacts)
}
report (names of contacts) map (name from contact: ()) over (contacts list)
  8. This new multiple-choice quizlet misbehaves if you only select some of the correct responses. Need to fix. --MF, 1/13/21

    Consider this list of squares:
    set (squares) to {1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225}
    Which of the following expressions will report a list? Choose all that apply.

    map (sqrt of()) over (squares)
    keep items (()mod(2)=0) from (squares)
    combine (squares) using (()+())
    keep items (letter (length of ()) of () = 1) from (squares)
    combine (squares) using (join ()()) items of
    map ((0)-()) over (squares)
  1. Click the picture to load this database project:
    Data from Structure and Interpretation of Computer Programs by Abelson and Sussman. Creative Commons licensed.
    list block containing nine instances of the constructor 'employee, name: () job title: () salary: ()' each with various inputs
    This is the list of employees of a small company. Each of the smaller lists contains a person's name, job title, and yearly salary.

    "This company spends more money on the big bosses than on the people who do the work," says Alyssa one day. Is she right? Write an expression to compute the total salaries of everyone paid less than $100,000 per year. Then find the total for everyone paid more than $100,000 per year.

  2. Ben suggests that the results will be more convincing in the form of a list containing that total and all the names of the people in that category (paid less than $100,000, for example). So, if there are five people in that category, your list will have six items: first the total of the salaries, and then the names of the people. Try this both for less than $100,000 and for more than $100,000.
  3. Find the average salary of people paid less than $100,000 per year.