{ }codelper
함수를 값으로목록 돌기음수 나머지P0239

규칙 함수를 넘겨 다듬는 수 목록

정수 목록을 규칙 s개로 차례차례 다듬는다. 첫 줄에 n이, 둘째 줄에 정수 n개가 빈칸으로 띄워 주어진다. 셋째 줄에 s가, 다음 s줄에 규칙이 한 줄에 하나씩 "이름 k" 꼴로 주어진다. 규칙은 여섯 가지이고, 앞의 셋은 목록의 모든 수를 바꾸고 뒤의 셋은 조건에 맞는 수만 남긴다. add k: 모든 수 x를 x + k로 바꾼다. mul k: 모든 수 x를 x × k로 바꾼다. mod k: 모든 수 x를, x를 k로 나눈 나머지 r로 바꾼다.
여기서 r은 0 이상 k 미만이고 x - r은 k의 배수다.
그래서 -7을 3으로 나눈 나머지는 2다. gt k: k보다 큰 수만 남긴다. lt k: k보다 작은 수만 남긴다. div k: k의 배수만 남긴다.
0과 음수도 k의 배수일 수 있다. 남는 수들의 차례는 그대로다. 규칙을 하나 쓸 때마다, 그 규칙까지 쓴 목록을 한 줄에 빈칸 하나씩 띄워 출력하라. 목록이 비면 -를 출력하고, 빈 목록에 다음 규칙을 써도 빈 목록이다. 풀이에는 "목록, 규칙 함수, k"를 받아 새 목록을 돌려주는 함수 두 개를 만들어라.
하나는 모든 수를 바꾸는 함수이고, 하나는 조건에 맞는 수만 남기는 함수다. 규칙마다 그 규칙의 함수를 값으로 넘겨 이 두 함수를 부른다.

입력
1 ≤ n ≤ 300, 1 ≤ s ≤ 20, 처음 수는 -1,000,000 이상 1,000,000 이하.
add는 -1,000,000 ≤ k ≤ 1,000,000, mul은 -10 ≤ k ≤ 10, mod는 1 ≤ k ≤ 1,000, gt·lt는 -1,000,000,000 ≤ k ≤ 1,000,000,000, div는 1 ≤ k ≤ 100.
어느 단계에서나 목록의 모든 수의 절댓값은 1,000,000,000 이하다
출력
규칙마다 한 줄: 그때의 목록, 비었으면 -
예시 1 · stdin
5
3 -7 10 0 5
4
mul 2
mod 4
gt 0
add -1
stdout
6 -14 20 0 10
2 2 0 0 2
2 2 2
1 1 1
예시 2 · stdin
4
2 4 6 1
2
div 2
lt 0
stdout
2 4 6
-
main.py
입력(stdin)

실행하면 이 줄들이 차례로 input()·표준 입력으로 들어가요(실행 중에 묻지 않아요).

$ 준비됐어요

코드를 입력해 풀려면 PC에서 열어 주세요. 모바일에서는 문제와 풀이를 볼 수 있어요.

다른 언어로는?언어별 풀이 보기 · 8개 언어 풀이

함수를 값으로 넘기는 방법이 언어마다 달라요.
Python은 def로 만든 함수 이름이나 lambda x, k: x + k를 그대로 넘기고, JS·TS는 화살표 함수 (x, k) => x + k를 넘겨요(TS는 (x: number, k: number) => number 같은 함수 타입을 붙여요).
Java는 람다를 받을 함수형 인터페이스가 있어야 해서 IntBinaryOperator, BiPredicate<Integer, Integer>를 쓰고, C#은 Func<int, int, int>, Func<int, int, bool>을 써요.
C는 함수 포인터 int (*rule)(int, int)로 넘기고, C++는 std::function<int(int, int)>에 람다를 담아요.
크레이콘에는 람다가 없어서 더하기(x, k)처럼 이름을 붙여 만든 함수를 이름으로 넘기고, 사전()에 이름 → 함수를 담아 골라요.
첫째 함정은 음수의 나머지예요.
JS·TS·Java·C#·C·C++·크레이콘의 %는 나누어지는 수의 부호를 따라서 -7 % 3이 -1이에요.
Python의 %만 2를 줘요.
(x % k + k) % k로 고치거나 Java Math.floorMod(x, k)를 써요.
둘째 함정은 걸러 내는 방법이에요.
Python에서 for x in a: 안에서 a.remove(x)를 하면 뒤의 칸이 당겨져 와서 바로 다음 수를 건너뛰니, 남길 수를 새 목록에 담아요.
JS·TS의 map·filter와 이 문제의 두 함수는 새 목록을 돌려주니, 돌려받은 목록을 다시 담지 않으면 아무것도 바뀌지 않아요.
gt·lt는 k와 같은 수를 남기지 않으니 >=·<=가 아니라 >·<예요.

Pythonmain.py · 41 줄
# 모든 수를 바꾸는 규칙(x, k → 새 수)def add(x, k):    return x + k def mul(x, k):    return x * k def mod(x, k):    return x % k  # Python의 %는 k가 양수면 늘 0 이상 k 미만 # 남길지 정하는 규칙(x, k → 참·거짓)def gt(x, k):    return x > k def lt(x, k):    return x < k def div(x, k):    return x % k == 0 # 함수를 값으로 받는 함수 두 개def change_all(a, rule, k):    return [rule(x, k) for x in a] def keep_only(a, rule, k):    return [x for x in a if rule(x, k)] CHANGE = {"add": add, "mul": mul, "mod": mod}KEEP = {"gt": gt, "lt": lt, "div": div} n = int(input())a = list(map(int, input().split()))s = int(input())for _ in range(s):    name, k = input().split()    k = int(k)    if name in CHANGE:        a = change_all(a, CHANGE[name], k)    else:        a = keep_only(a, KEEP[name], k)    print(" ".join(map(str, a)) if a else "-")
JavaScriptmain.js · 28 줄
const lines = require("fs").readFileSync(0, "utf8").split("\n");// 모든 수를 바꾸는 규칙(x, k → 새 수). JS의 %는 음수에서 음수가 나오니 k를 더해 한 번 더 나눈다const CHANGE = {  add: (x, k) => x + k,  mul: (x, k) => x * k,  mod: (x, k) => ((x % k) + k) % k,};// 남길지 정하는 규칙(x, k → 참·거짓)const KEEP = {  gt: (x, k) => x > k,  lt: (x, k) => x < k,  div: (x, k) => x % k === 0,};// 함수를 값으로 받는 함수 두 개. map·filter는 새 배열을 돌려준다const changeAll = (a, rule, k) => a.map((x) => rule(x, k));const keepOnly = (a, rule, k) => a.filter((x) => rule(x, k)); let a = lines[1].trim().split(/\s+/).map(Number);const s = Number(lines[2]);const out = [];for (let i = 0; i < s; i++) {  const [name, ks] = lines[3 + i].trim().split(/\s+/);  const k = Number(ks);  a = name in CHANGE ? changeAll(a, CHANGE[name], k) : keepOnly(a, KEEP[name], k);  // -0 % 3은 -0이지만 join은 "0"으로 쓴다  out.push(a.length ? a.join(" ") : "-");}console.log(out.join("\n"));
TypeScriptmain.ts · 30 줄
import { readFileSync } from "node:fs";const lines: string[] = readFileSync(0, "utf8").split("\n");type Change = (x: number, k: number) => number;type Keep = (x: number, k: number) => boolean;// 모든 수를 바꾸는 규칙. JS·TS의 %는 음수에서 음수가 나오니 k를 더해 한 번 더 나눈다const CHANGE: Record<string, Change> = {  add: (x, k) => x + k,  mul: (x, k) => x * k,  mod: (x, k) => ((x % k) + k) % k,};// 남길지 정하는 규칙const KEEP: Record<string, Keep> = {  gt: (x, k) => x > k,  lt: (x, k) => x < k,  div: (x, k) => x % k === 0,};// 함수를 값으로 받는 함수 두 개const changeAll = (a: number[], rule: Change, k: number): number[] => a.map((x) => rule(x, k));const keepOnly = (a: number[], rule: Keep, k: number): number[] => a.filter((x) => rule(x, k)); let a: number[] = lines[1].trim().split(/\s+/).map(Number);const s: number = Number(lines[2]);const out: string[] = [];for (let i = 0; i < s; i++) {  const [name, ks] = lines[3 + i].trim().split(/\s+/);  const k: number = Number(ks);  a = name in CHANGE ? changeAll(a, CHANGE[name], k) : keepOnly(a, KEEP[name], k);  out.push(a.length ? a.join(" ") : "-");}console.log(out.join("\n"));
JavaMain.java · 56 줄
import java.io.BufferedReader;import java.io.InputStreamReader;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.StringTokenizer;import java.util.function.BiPredicate;import java.util.function.IntBinaryOperator; public class Main {    // 함수를 값으로 받는 함수 두 개    static List<Integer> changeAll(List<Integer> a, IntBinaryOperator rule, int k) {        List<Integer> b = new ArrayList<>();        for (int x : a) b.add(rule.applyAsInt(x, k));        return b;    }     static List<Integer> keepOnly(List<Integer> a, BiPredicate<Integer, Integer> rule, int k) {        List<Integer> b = new ArrayList<>();        for (int x : a) if (rule.test(x, k)) b.add(x);        return b;    }     public static void main(String[] args) throws Exception {        Map<String, IntBinaryOperator> change = new HashMap<>();        change.put("add", (x, k) -> x + k);        change.put("mul", (x, k) -> x * k);        change.put("mod", Math::floorMod); // %는 음수에서 음수가 나온다. floorMod는 0 이상 k 미만        Map<String, BiPredicate<Integer, Integer>> keep = new HashMap<>();        keep.put("gt", (x, k) -> x > k);        keep.put("lt", (x, k) -> x < k);        keep.put("div", (x, k) -> x % k == 0);         BufferedReader in = new BufferedReader(new InputStreamReader(System.in));        in.readLine();        List<Integer> a = new ArrayList<>();        StringTokenizer st = new StringTokenizer(in.readLine());        while (st.hasMoreTokens()) a.add(Integer.parseInt(st.nextToken()));        int s = Integer.parseInt(in.readLine().trim());        StringBuilder out = new StringBuilder();        for (int i = 0; i < s; i++) {            st = new StringTokenizer(in.readLine());            String name = st.nextToken();            int k = Integer.parseInt(st.nextToken());            a = change.containsKey(name) ? changeAll(a, change.get(name), k) : keepOnly(a, keep.get(name), k);            if (a.isEmpty()) {                out.append("-\n");                continue;            }            for (int j = 0; j < a.size(); j++) out.append(j > 0 ? " " : "").append(a.get(j));            out.append('\n');        }        System.out.print(out);    }}
C#Main.cs · 50 줄
using System;using System.Collections.Generic;using System.Text; class Program{    // 함수를 값으로 받는 함수 두 개    static List<int> ChangeAll(List<int> a, Func<int, int, int> rule, int k)    {        var b = new List<int>();        foreach (int x in a) b.Add(rule(x, k));        return b;    }     static List<int> KeepOnly(List<int> a, Func<int, int, bool> rule, int k)    {        var b = new List<int>();        foreach (int x in a) if (rule(x, k)) b.Add(x);        return b;    }     static void Main()    {        var change = new Dictionary<string, Func<int, int, int>>        {            ["add"] = (x, k) => x + k,            ["mul"] = (x, k) => x * k,            ["mod"] = (x, k) => ((x % k) + k) % k, // %는 음수에서 음수가 나온다        };        var keep = new Dictionary<string, Func<int, int, bool>>        {            ["gt"] = (x, k) => x > k,            ["lt"] = (x, k) => x < k,            ["div"] = (x, k) => x % k == 0,        };        Console.ReadLine();        var a = new List<int>();        foreach (string t in Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries)) a.Add(int.Parse(t));        int s = int.Parse(Console.ReadLine());        var sb = new StringBuilder();        for (int i = 0; i < s; i++)        {            string[] p = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries);            int k = int.Parse(p[1]);            a = change.TryGetValue(p[0], out var f) ? ChangeAll(a, f, k) : KeepOnly(a, keep[p[0]], k);            sb.Append(a.Count > 0 ? string.Join(" ", a) : "-").Append('\n');        }        Console.Write(sb);    }}
C++main.cpp · 48 줄
#include <functional>#include <iostream>#include <map>#include <string>#include <vector> using Change = std::function<int(int, int)>;using Keep = std::function<bool(int, int)>; // 함수를 값으로 받는 함수 두 개std::vector<int> changeAll(const std::vector<int> &a, const Change &rule, int k) {    std::vector<int> b;    for (int x : a) b.push_back(rule(x, k));    return b;} std::vector<int> keepOnly(const std::vector<int> &a, const Keep &rule, int k) {    std::vector<int> b;    for (int x : a) if (rule(x, k)) b.push_back(x);    return b;} int main() {    const std::map<std::string, Change> change = {        {"add", [](int x, int k) { return x + k; }},        {"mul", [](int x, int k) { return x * k; }},        {"mod", [](int x, int k) { return (x % k + k) % k; }}, // %는 음수에서 음수가 나온다    };    const std::map<std::string, Keep> keep = {        {"gt", [](int x, int k) { return x > k; }},        {"lt", [](int x, int k) { return x < k; }},        {"div", [](int x, int k) { return x % k == 0; }},    };    int n, s, k;    std::cin >> n;    std::vector<int> a(n);    for (int &x : a) std::cin >> x;    std::cin >> s;    std::string name;    for (int i = 0; i < s; i++) {        std::cin >> name >> k;        auto it = change.find(name);        a = it != change.end() ? changeAll(a, it->second, k) : keepOnly(a, keep.at(name), k);        if (a.empty()) std::cout << '-';        for (std::size_t j = 0; j < a.size(); j++) std::cout << (j ? " " : "") << a[j];        std::cout << '\n';    }}
Cmain.c · 46 줄
#include <stdio.h>#include <string.h> /* 모든 수를 바꾸는 규칙과 남길지 정하는 규칙. 함수 포인터로 넘긴다 */int add(int x, int k) { return x + k; }int mul(int x, int k) { return x * k; }int mod(int x, int k) { return (x % k + k) % k; } /* C의 %는 음수에서 음수가 나온다 */int gt(int x, int k) { return x > k; }int lt(int x, int k) { return x < k; }int divisible(int x, int k) { return x % k == 0; } /* 함수를 값으로 받는 함수 두 개. 남긴 개수를 돌려준다 */int change_all(int *a, int n, int (*rule)(int, int), int k) {    for (int i = 0; i < n; i++) a[i] = rule(a[i], k);    return n;} int keep_only(int *a, int n, int (*rule)(int, int), int k) {    int m = 0;    for (int i = 0; i < n; i++) {        if (rule(a[i], k)) a[m++] = a[i]; /* 앞으로 당겨 담는다 */    }    return m;} int main(void) {    struct { const char *name; int (*fn)(int, int); int changes; } rules[] = {        {"add", add, 1}, {"mul", mul, 1}, {"mod", mod, 1},        {"gt", gt, 0}, {"lt", lt, 0}, {"div", divisible, 0},    };    int n, s, k, a[300];    char name[8];    scanf("%d", &n);    for (int i = 0; i < n; i++) scanf("%d", &a[i]);    scanf("%d", &s);    for (int step = 0; step < s; step++) {        scanf("%7s %d", name, &k);        for (int r = 0; r < 6; r++) {            if (strcmp(rules[r].name, name) != 0) continue;            n = rules[r].changes ? change_all(a, n, rules[r].fn, k) : keep_only(a, n, rules[r].fn, k);        }        if (n == 0) puts("-");        for (int i = 0; i < n; i++) printf(i + 1 < n ? "%d " : "%d\n", a[i]);    }    return 0;}
Craykonmain.cray · 90 줄
// 모든 수를 바꾸는 규칙(x, k → 새 수)더하기(x, k){    돌려주기 x + k;} 곱하기(x, k){    돌려주기 x * k;} 나머지(x, k){    // 크레이콘의 %는 음수에서 음수가 나오니 k를 더해 한 번 더 나눈다    돌려주기 (x % k + k) % k;} // 남길지 정하는 규칙(x, k → 참·거짓)큰것만(x, k){    돌려주기 x > k;} 작은것만(x, k){    돌려주기 x < k;} 배수만(x, k){    돌려주기 x % k == 0;} // 함수를 값으로 받는 함수 두 개. 크레이콘에는 람다가 없으니 이름으로 넘긴다모두바꾸기(a, 규칙, k){    b = [];    각각 (x 에서 a)    {        b.넣기(규칙(x, k));    }    돌려주기 b;} 골라남기기(a, 규칙, k){    b = [];    각각 (x 에서 a)    {        만약 (규칙(x, k))        {            b.넣기(x);        }    }    돌려주기 b;} change = 사전();change["add"] = 더하기;change["mul"] = 곱하기;change["mod"] = 나머지;keep = 사전();keep["gt"] = 큰것만;keep["lt"] = 작은것만;keep["div"] = 배수만; 콘솔.줄읽기();a = 콘솔.수들읽기();s = 콘솔.줄읽기().수로변환();반복 (i = 0; i < s; i++){    p = 콘솔.줄읽기().나누기();    k = p[1].수로변환();    만약 (change.있나(p[0]))    {        a = 모두바꾸기(a, change[p[0]], k);    }    아니면    {        a = 골라남기기(a, keep[p[0]], k);    }    만약 (a.개수 == 0)    {        콘솔.쓰기("-");    }    아니면    {        콘솔.쓰기(a.잇기(" "));    }}