{ }codelper
functions as valuesP0318

Pick the top word with a key function passed in

There are n words and four keys, each turning a word into a number. len is the number of letters in the word. vowels is how many of the vowels a, e, i, o, u the word contains. kinds is the number of different letters used in the word. last is the position of the word's last letter in the alphabet (a is 1, z is 26). Write just one function that receives the list of words and one key function and returns the word whose key value is the largest, and use it for all four keys. If several words have the largest value, choose the one that appears first in the input. The first line gives n and the number of questions q, separated by a single space. The second line gives the n words, separated by single spaces. Each of the next q lines gives one key name. For each question, print the chosen word and its value on one line, separated by a single space.

Input
1 ≤ n ≤ 100, 1 ≤ q ≤ 100.
Each word is a string of 1 to 20 lowercase English letters, and the same word may appear more than once.
Each key name is one of len, vowels, kinds, last
Output
q lines: the chosen word and its value for each question
Example 1 · stdin
6 4
kiwi banana fig queue papaya jazz
len
vowels
kinds
last
stdout
banana 6
queue 4
kiwi 3
jazz 26
main.py
Input (stdin)

When you run, these lines are fed to input()/stdin in order (the program doesn't stop to ask).

$ Ready

Open this on a computer to write and run code. On mobile you can read the problem and the solutions.

In other languagesShow solutions by language · 8 languages

This problem is about passing a function to another function as a value.
When you pass it, you do not put parentheses after its name.
Python has a built-in that takes a key function, max(words, key=count_vowels), and C# has words.MaxBy(key).
Both give the earliest item when values are equal.
The type that holds a function differs by language: TS type Key = (w: string) => number, Java ToIntFunction<String> (you point at a method with Main::countVowels and call it with key.applyAsInt(w)), C# Func<string, int>, C a function pointer int (*key)(const char *), C++ std::function<int(const std::string&)>.
Python, JS and Craykon write no type and just pass it.
Making a nameless function (lambda) on the spot also differs: Python lambda w: len(w), JS/TS/C# w => w.length, Java w -> w.length(), C++ [](const std::string& w) { return (int)w.size(); }.
Craykon and C have no lambdas, so you define a named function and store it by writing only its name, as in keys["len"] = Letters.
Java Collections.max(words, Comparator.comparingInt(key)) and C++ std::max_element take a comparing function and give the earliest item when values are equal.
Three traps: (1) If you search with a loop and compare with >=, you switch every time an equal word appears, so the last one remains (in the example len becomes papaya 6 and kinds becomes jazz 3).
Use >.
(2) Sorting and taking the end, Python sorted(words, key=key)[-1], also gives the last of the equal words, because sorting keeps the original order of items with equal values.
C++ std::minmax_element(...).second also points at the last of the largest.
(3) In JS, writing parentheses as in best(words, key(words[0])) passes not the function but the result of calling it right there (a number).
Inside best the program tries to call that number and stops with key is not a function.

Pythonmain.py · 27 lines
def count_vowels(w):    return sum(1 for c in w if c in "aeiou")  def count_kinds(w):    return len(set(w))  def last_rank(w):    return ord(w[-1]) - ord("a") + 1  # 기준 이름으로 함수를 찾는 표. 이름 뒤에 괄호를 붙이지 않는다(부르지 않고 함수 자체를 담는다)KEYS = {"len": len, "vowels": count_vowels, "kinds": count_kinds, "last": last_rank}  def best(words, key):    # max는 key 함수로 잰 값이 가장 큰 것을 돌려주고, 값이 같으면 먼저 나온 것을 돌려준다    return max(words, key=key)  n, q = map(int, input().split())words = input().split()for _ in range(q):    key = KEYS[input().strip()]    w = best(words, key)    print(w, key(w))
JavaScriptmain.js · 28 lines
const lines = require("fs").readFileSync(0, "utf8").split("\n"); // 기준 이름으로 함수를 찾는 표. 화살표 함수는 그대로 값이다const KEYS = {  len: (w) => w.length,  vowels: (w) => [...w].filter((c) => "aeiou".includes(c)).length,  kinds: (w) => new Set(w).size,  last: (w) => w.charCodeAt(w.length - 1) - "a".charCodeAt(0) + 1,}; // 낱말 목록과 기준 함수를 받는다. 더 클 때만(>) 바꾸므로 값이 같으면 먼저 나온 낱말이 남는다function best(words, key) {  let top = words[0];  for (const w of words) {    if (key(w) > key(top)) top = w;  }  return top;} const [n, q] = lines[0].trim().split(/\s+/).map(Number);const words = lines[1].trim().split(/\s+/);const out = [];for (let i = 0; i < q; i++) {  const key = KEYS[lines[2 + i].trim()];  const w = best(words, key);  out.push(w + " " + key(w));}console.log(out.join("\n"));
TypeScriptmain.ts · 32 lines
import { readFileSync } from "node:fs";const lines: string[] = readFileSync(0, "utf8").split("\n"); // 함수의 타입: 낱말을 받아 수를 돌려준다type Key = (w: string) => number; // 기준 이름으로 함수를 찾는 표. 화살표 함수는 그대로 값이다const KEYS: Record<string, Key> = {  len: (w) => w.length,  vowels: (w) => [...w].filter((c) => "aeiou".includes(c)).length,  kinds: (w) => new Set(w).size,  last: (w) => w.charCodeAt(w.length - 1) - "a".charCodeAt(0) + 1,}; // 낱말 목록과 기준 함수를 받는다. 더 클 때만(>) 바꾸므로 값이 같으면 먼저 나온 낱말이 남는다function best(words: string[], key: Key): string {  let top: string = words[0];  for (const w of words) {    if (key(w) > key(top)) top = w;  }  return top;} const [n, q]: number[] = lines[0].trim().split(/\s+/).map(Number);const words: string[] = lines[1].trim().split(/\s+/);const out: string[] = [];for (let i = 0; i < q; i++) {  const key: Key = KEYS[lines[2 + i].trim()];  const w: string = best(words, key);  out.push(w + " " + key(w));}console.log(out.join("\n"));
JavaMain.java · 55 lines
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.util.Arrays;import java.util.Collections;import java.util.Comparator;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.StringTokenizer;import java.util.function.ToIntFunction; public class Main {    static int countVowels(String w) {        int count = 0;        for (char c : w.toCharArray()) if ("aeiou".indexOf(c) >= 0) count++;        return count;    }     static int countKinds(String w) {        return (int) w.chars().distinct().count();    }     static int lastRank(String w) {        return w.charAt(w.length() - 1) - 'a' + 1;    }     // 낱말 목록과 기준 함수를 받는다. Collections.max는 값이 같으면 먼저 나온 것을 돌려준다    static String best(List<String> words, ToIntFunction<String> key) {        return Collections.max(words, Comparator.comparingInt(key));    }     public static void main(String[] args) throws IOException {        // 함수를 값으로 담는 타입이 ToIntFunction<String>이다. 메서드는 "클래스::이름"으로 가리킨다        Map<String, ToIntFunction<String>> keys = new HashMap<>();        keys.put("len", String::length);        keys.put("vowels", Main::countVowels);        keys.put("kinds", Main::countKinds);        keys.put("last", Main::lastRank);         BufferedReader in = new BufferedReader(new InputStreamReader(System.in));        StringTokenizer st = new StringTokenizer(in.readLine());        int n = Integer.parseInt(st.nextToken());        int q = Integer.parseInt(st.nextToken());        List<String> words = Arrays.asList(in.readLine().trim().split(" +"));        StringBuilder out = new StringBuilder();        for (int i = 0; i < q; i++) {            ToIntFunction<String> key = keys.get(in.readLine().trim());            String w = best(words, key);            // 담아 둔 함수는 key(w)가 아니라 key.applyAsInt(w)로 부른다            out.append(w).append(' ').append(key.applyAsInt(w)).append('\n');        }        System.out.print(out);    }}
C#Main.cs · 36 lines
using System;using System.Collections.Generic;using System.Linq;using System.Text; class Program{    static int CountVowels(string w) => w.Count(c => "aeiou".Contains(c));    static int CountKinds(string w) => w.Distinct().Count();    static int LastRank(string w) => w[w.Length - 1] - 'a' + 1;     // 낱말 목록과 기준 함수를 받는다. MaxBy는 값이 같으면 먼저 나온 것을 돌려준다    static string Best(string[] words, Func<string, int> key) => words.MaxBy(key);     static void Main()    {        // 함수를 값으로 담는 타입이 Func<string, int>이다(string을 받아 int를 돌려주는 함수)        var keys = new Dictionary<string, Func<string, int>>        {            ["len"] = w => w.Length,            ["vowels"] = CountVowels,            ["kinds"] = CountKinds,            ["last"] = LastRank,        };        int q = int.Parse(Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries)[1]);        string[] words = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries);        var sb = new StringBuilder();        for (int i = 0; i < q; i++)        {            Func<string, int> key = keys[Console.ReadLine().Trim()];            string best = Best(words, key);            sb.Append(best).Append(' ').Append(key(best)).Append('\n');        }        Console.Write(sb);    }}
C++main.cpp · 39 lines
#include <algorithm>#include <functional>#include <iostream>#include <map>#include <set>#include <string>#include <vector> // 함수를 값으로 담는 타입: 낱말을 받아 int를 돌려주는 것이면 함수든 람다든 담긴다using Key = std::function<int(const std::string&)>; // 낱말 목록과 기준 함수를 받는다. max_element는 값이 같으면 먼저 나온 것을 가리킨다const std::string& best(const std::vector<std::string>& words, const Key& key) {    return *std::max_element(words.begin(), words.end(),                             [&](const std::string& a, const std::string& b) { return key(a) < key(b); });} int main() {    std::map<std::string, Key> keys = {        {"len", [](const std::string& w) { return (int)w.size(); }},        {"vowels", [](const std::string& w) {             return (int)std::count_if(w.begin(), w.end(), [](char c) { return std::string("aeiou").find(c) != std::string::npos; });         }},        {"kinds", [](const std::string& w) { return (int)std::set<char>(w.begin(), w.end()).size(); }},        {"last", [](const std::string& w) { return w.back() - 'a' + 1; }},    };     int n, q;    std::cin >> n >> q;    std::vector<std::string> words(n);    for (auto& w : words) std::cin >> w;    for (int i = 0; i < q; i++) {        std::string name;        std::cin >> name;        const Key& key = keys[name];        const std::string& w = best(words, key);        std::cout << w << ' ' << key(w) << '\n';    }}
Cmain.c · 61 lines
#include <stdio.h>#include <string.h> static int length_of(const char *w) {    return (int)strlen(w);} static int count_vowels(const char *w) {    int count = 0;    for (; *w; w++) if (strchr("aeiou", *w)) count++;    return count;} static int count_kinds(const char *w) {    int seen[26] = {0}, count = 0;    for (; *w; w++) {        if (!seen[*w - 'a']) {            seen[*w - 'a'] = 1;            count++;        }    }    return count;} static int last_rank(const char *w) {    return w[strlen(w) - 1] - 'a' + 1;} /* 함수 포인터 타입: 낱말을 받아 int를 돌려주는 함수를 가리킨다 */typedef int (*key_fn)(const char *); /* 낱말 목록과 기준 함수를 받는다. 더 클 때만(>) 바꾸므로 값이 같으면 먼저 나온 낱말이 남는다 */static const char *best(char words[][21], int n, key_fn key) {    const char *top = words[0];    for (int i = 1; i < n; i++) {        if (key(words[i]) > key(top)) top = words[i];    }    return top;} int main(void) {    /* 기준 이름과 함수를 짝지은 표. 함수 이름만 쓰면 그 함수의 주소다 */    const char *names[] = {"len", "vowels", "kinds", "last"};    key_fn keys[] = {length_of, count_vowels, count_kinds, last_rank};     int n, q;    static char words[100][21];    scanf("%d %d", &n, &q);    for (int i = 0; i < n; i++) scanf("%20s", words[i]);    for (int i = 0; i < q; i++) {        char name[16];        scanf("%15s", name);        for (int k = 0; k < 4; k++) {            if (strcmp(name, names[k]) == 0) {                const char *w = best(words, n, keys[k]);                printf("%s %d\n", w, keys[k](w));            }        }    }    return 0;}
Craykonmain.cray · 64 lines
// 기준 함수 네 개. 크레이콘에는 람다가 없어서 이름 있는 함수로 만든다글자수(w){    return w.Length;} 모음수(w){    count = 0;    foreach (c in w)    {        if ("aeiou".Contains(c))        {            count++;        }    }    return count;} 가짓수(w){    본것 = Dict();    foreach (c in w)    {        본것[c] = true;    }    return 본것.Count;} 끝글자순번(w){    return Str.Code(w[w.Length - 1]) - Str.Code("a") + 1;} // 낱말 목록과 기준 함수를 받는다. 더 클 때만(>) 바꾸므로 값이 같으면 먼저 나온 낱말이 남는다으뜸(낱말들, 기준){    top = 낱말들[0];    foreach (w in 낱말들)    {        if (기준(w) > 기준(top))        {            top = w;        }    }    return top;} // 함수 이름을 괄호 없이 쓰면 함수 자체가 값으로 담긴다keys = Dict();keys["len"] = 글자수;keys["vowels"] = 모음수;keys["kinds"] = 가짓수;keys["last"] = 끝글자순번; 첫줄 = Console.ReadNumbers();q = 첫줄[1];words = Console.ReadLine().Trim().Split();for (i = 0; i < q; i++){    key = keys[Console.ReadLine().Trim()];    w = 으뜸(words, key);    Console.WriteLine(w + " " + key(w));}