{ }codelper
parametersP0361

Binding Named Arguments

You are given the parameter list of one function and several calls of that function. For each call, decide which parameter each argument goes to and print the values the parameters receive. The first line has the number of parameters p, and the next p lines have the parameters in declaration order, one per line. A parameter line is one of "name", "name integer" and "name earlier". "name" alone is a parameter with no default, and "name integer" is a parameter whose default is that integer. "name earlier" is a parameter whose default is the value that the parameter earlier received in that call, where earlier is the name of a parameter declared on an earlier line. The next line has the number of calls q, and the next q lines have the calls, one per line. A call line starts with call, followed by zero or more arguments separated by single spaces. An argument is either a positional argument, which is one integer, or a named argument of the form "name=integer". For each call, process the arguments one by one from the left. The k-th positional argument of the call goes to the k-th declared parameter, and a named argument goes to the parameter with that name. If one of the errors below is met while processing, print only that one error line and do not look at the rest of the call's arguments. If a positional argument comes after a named argument, the error is "error order". Otherwise, if there are more than p positional arguments, the error is "error many". If the name of a named argument is not a parameter, the error is "error unknown name". If the name exists but that parameter has already received a value in this call, the error is "error twice name". When all arguments are processed without an error, fill the parameters that received no value with their defaults, in declaration order. If a parameter with no default is met while filling, print "error missing name" and end that call. If there is no error, print the values received by the p parameters in declaration order on one line, separated by single spaces. Calls do not affect each other.

Input
1 ≤ p ≤ 8, 1 ≤ q ≤ 1,000.
Names are 1 to 8 lowercase English letters; parameter names are distinct and are not call.
Every integer is between −1,000,000,000 and 1,000,000,000, and a negative one starts with -.
A call has at most 12 arguments.
A named argument has no spaces around =
Output
One line per call: the p values, or error order · error many · error unknown name · error twice name · error missing name
Example 1 · stdin
4
w
h w
depth 0
pad
10
call 3 pad=1
call 0 0 0 0
call 5 w=0
call 0 w=5
call pad=2 4 nope=1
call h=7
call 1 2 3 4 5
call 2 dept=1 pad=0
call 6 depth=0 depth=4 pad=1
call 9 h=0 pad=0
stdout
3 3 0 1
0 0 0 0
error twice w
error twice w
error order
error missing w
error many
error unknown dept
error twice depth
9 0 0 0
Example 2 · stdin
3
base 10
low base
high low
4
call
call 4
call low=0
call high=1 base=2
stdout
10 10 10
4 4 4
10 0 0
2 2 1
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 builds by hand the named argument and default value rules that Python and C# have.
In the real languages it goes like this.
Python calls def box(w, h=None, depth=0, *, pad) as box(3, pad=1).
box(5, w=0) is a TypeError (got multiple values for argument 'w'), an unknown name dept=1 is also a TypeError, and box(pad=2, 4) is a SyntaxError before anything runs (positional argument follows keyword argument).
C# writes Box(3, pad: 1); Box(5, w: 0) is compile error CS1744 and Box(h: 2, 4) is CS8323 (a positional argument may follow a named one that is in its own position, as in Box(w: 1, 2)).
JS and TS have no named arguments, so you pass one object and unpack it with function box({ w, h = w, depth = 0, pad }).
In JS box({ w: 1, w: 2 }) gives no error and the later value wins, and an unknown key dept is silently dropped.
Java, C++, C and Craykon have no named arguments.
C imitates them with a struct, box((struct Box){ .w = 3, .pad = 1 }), but the members you leave out become 0, so 'not given' and 'given 0' cannot be told apart.
Defaults differ too.
C++ int h = 0 is allowed only on trailing parameters, and int h = w is a compile error.
In Python def g(w, h=w) is a NameError as well, so you take h=None and fill it with if h is None: h = w.
JS and TS accept function pos(w, h = w) and compute it on every call.
Java and Craykon have no defaults: Java declares several functions with the same name, and Craykon stops when the number of values differs.
Trap one: a given value can be 0.
If you ask 'has a value been given' by the truth of the value, as in Python if values[i]:, a slot holding 0 looks empty and call 0 w=5 passes without an error.
Ask with Python is None, JS/TS === null, HasValue of C# int?, null of Java Integer, has_value() of C++ std::optional, a separate bool array in C, or != null in Craykon.
Python h = h or w and JS h = h || w are the same trap: a given 0 is replaced by the default.
Trap two: a default of 0 is still a default.
Asking with JS if (defaultValue[i]) turns depth 0 into a parameter with no default.
Trap three: the default of h w is the value w received in that call.
If you copy the earlier parameter's default while reading the declarations, call 4 in the second example becomes 4 10 10.
Fill the parameters in order from the first.
Trap four: the error is the single first one met while reading the arguments from the left.
Scanning once per kind of error gives unknown instead of order for call pad=2 4 nope=1.
missing is also the first in declaration order, so call h=7 reports w, not pad.
Trap five: names must match as a whole.
Comparing only the front, as in C strncmp(names[i], name, strlen(name)), lets dept pass as depth.

Pythonmain.py · 64 lines
import sys  def bind(names, default_value, default_from, args):    """인자를 매개변수에 맞춰 넣는다. (값 목록, "") 또는 (None, 오류)를 돌려준다."""    p = len(names)    values = [None] * p  # None = 아직 값이 들어가지 않음(0도 들어간 값이다)    positional = 0    seen_named = False    for arg in args:        if "=" in arg:            seen_named = True            name, text = arg.split("=")            if name not in names:                return None, "unknown " + name            i = names.index(name)            if values[i] is not None:                return None, "twice " + name            values[i] = int(text)        else:            if seen_named:                return None, "order"            if positional == p:                return None, "many"            values[positional] = int(arg)            positional += 1    for i in range(p):  # 앞에서부터 채워야 앞 매개변수의 값을 기본값으로 쓸 수 있다        if values[i] is None:            if default_from[i] >= 0:                values[i] = values[default_from[i]]            elif default_value[i] is not None:                values[i] = default_value[i]            else:                return None, "missing " + names[i]    return values, ""  def main():    lines = sys.stdin.read().split("\n")    p = int(lines[0])    names, default_value, default_from = [], [], []    for line in lines[1:1 + p]:        parts = line.split()        value, source = None, -1        if len(parts) == 2:            if parts[1][0].isalpha():                source = names.index(parts[1])            else:                value = int(parts[1])        names.append(parts[0])        default_value.append(value)        default_from.append(source)    q = int(lines[1 + p])    out = []    for line in lines[2 + p:2 + p + q]:        values, error = bind(names, default_value, default_from, line.split()[1:])        if values is None:            out.append("error " + error)        else:            out.append(" ".join(map(str, values)))    print("\n".join(out))  main()
JavaScriptmain.js · 56 lines
const lines = require("fs").readFileSync(0, "utf8").split("\n"); // 인자를 매개변수에 맞춰 넣는다. 값 배열 또는 오류 문자열을 돌려준다.function bind(names, defaultValue, defaultFrom, args) {  const p = names.length;  const values = new Array(p).fill(null); // null = 아직 값이 들어가지 않음(0도 들어간 값이다)  let positional = 0;  let seenNamed = false;  for (const arg of args) {    const eq = arg.indexOf("=");    if (eq >= 0) {      seenNamed = true;      const name = arg.slice(0, eq);      const i = names.indexOf(name);      if (i < 0) return "unknown " + name;      if (values[i] !== null) return "twice " + name;      values[i] = Number(arg.slice(eq + 1));    } else {      if (seenNamed) return "order";      if (positional === p) return "many";      values[positional++] = Number(arg);    }  }  for (let i = 0; i < p; i++) {    if (values[i] !== null) continue;    if (defaultFrom[i] >= 0) values[i] = values[defaultFrom[i]];    else if (defaultValue[i] !== null) values[i] = defaultValue[i];    else return "missing " + names[i];  }  return values;} const p = Number(lines[0]);const names = [];const defaultValue = [];const defaultFrom = [];for (let i = 1; i <= p; i++) {  const parts = lines[i].trim().split(" ");  let value = null;  let source = -1;  if (parts.length === 2) {    if (/^[a-z]/.test(parts[1])) source = names.indexOf(parts[1]);    else value = Number(parts[1]);  }  names.push(parts[0]);  defaultValue.push(value);  defaultFrom.push(source);}const q = Number(lines[p + 1]);const out = [];for (let i = 0; i < q; i++) {  const args = lines[p + 2 + i].trim().split(" ").slice(1);  const result = bind(names, defaultValue, defaultFrom, args);  out.push(typeof result === "string" ? "error " + result : result.join(" "));}console.log(out.join("\n"));
TypeScriptmain.ts · 62 lines
import { readFileSync } from "node:fs"; const lines: string[] = readFileSync(0, "utf8").split("\n"); // 인자를 매개변수에 맞춰 넣는다. 값 배열 또는 오류 문자열을 돌려준다.function bind(names: string[], defaultValue: (number | null)[], defaultFrom: number[], args: string[]): number[] | string {  const p = names.length;  const values: (number | null)[] = new Array<number | null>(p).fill(null); // null = 아직 값이 들어가지 않음  let positional = 0;  let seenNamed = false;  for (const arg of args) {    const eq = arg.indexOf("=");    if (eq >= 0) {      seenNamed = true;      const name = arg.slice(0, eq);      const i = names.indexOf(name);      if (i < 0) return "unknown " + name;      if (values[i] !== null) return "twice " + name;      values[i] = Number(arg.slice(eq + 1));    } else {      if (seenNamed) return "order";      if (positional === p) return "many";      values[positional++] = Number(arg);    }  }  const filled: number[] = [];  for (let i = 0; i < p; i++) {    let v: number | null = values[i];    if (v === null) {      if (defaultFrom[i] >= 0) v = filled[defaultFrom[i]];      else v = defaultValue[i];    }    if (v === null) return "missing " + names[i];    filled.push(v);  }  return filled;} const p: number = Number(lines[0]);const names: string[] = [];const defaultValue: (number | null)[] = [];const defaultFrom: number[] = [];for (let i = 1; i <= p; i++) {  const parts: string[] = lines[i].trim().split(" ");  let value: number | null = null;  let source = -1;  if (parts.length === 2) {    if (/^[a-z]/.test(parts[1])) source = names.indexOf(parts[1]);    else value = Number(parts[1]);  }  names.push(parts[0]);  defaultValue.push(value);  defaultFrom.push(source);}const q: number = Number(lines[p + 1]);const out: string[] = [];for (let i = 0; i < q; i++) {  const args: string[] = lines[p + 2 + i].trim().split(" ").slice(1);  const result = bind(names, defaultValue, defaultFrom, args);  out.push(typeof result === "string" ? "error " + result : result.join(" "));}console.log(out.join("\n"));
JavaMain.java · 72 lines
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.util.ArrayList;import java.util.List; public class Main {    static List<String> names = new ArrayList<>();    static List<Integer> defaultValue = new ArrayList<>(); // null = 기본값이 정수가 아님    static List<Integer> defaultFrom = new ArrayList<>();  // -1 = 앞 매개변수를 쓰지 않음     // 인자를 매개변수에 맞춰 넣는다. 오류가 없으면 values를 채우고 null을, 있으면 오류 문자열을 돌려준다.    static String bind(String[] args, Integer[] values) {        int p = names.size();        int positional = 0;        boolean seenNamed = false;        for (int a = 1; a < args.length; a++) {            String arg = args[a];            int eq = arg.indexOf('=');            if (eq >= 0) {                seenNamed = true;                String name = arg.substring(0, eq);                int i = names.indexOf(name);                if (i < 0) return "unknown " + name;                if (values[i] != null) return "twice " + name; // null = 아직 값이 들어가지 않음                values[i] = Integer.parseInt(arg.substring(eq + 1));            } else {                if (seenNamed) return "order";                if (positional == p) return "many";                values[positional++] = Integer.parseInt(arg);            }        }        for (int i = 0; i < p; i++) {            if (values[i] != null) continue;            if (defaultFrom.get(i) >= 0) values[i] = values[defaultFrom.get(i)];            else if (defaultValue.get(i) != null) values[i] = defaultValue.get(i);            else return "missing " + names.get(i);        }        return null;    }     public static void main(String[] argv) throws IOException {        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));        int p = Integer.parseInt(in.readLine().trim());        for (int i = 0; i < p; i++) {            String[] parts = in.readLine().trim().split(" ");            Integer value = null;            int source = -1;            if (parts.length == 2) {                if (Character.isLetter(parts[1].charAt(0))) source = names.indexOf(parts[1]);                else value = Integer.parseInt(parts[1]);            }            names.add(parts[0]);            defaultValue.add(value);            defaultFrom.add(source);        }        int q = Integer.parseInt(in.readLine().trim());        StringBuilder out = new StringBuilder();        for (int t = 0; t < q; t++) {            String[] args = in.readLine().trim().split(" ");            Integer[] values = new Integer[p];            String error = bind(args, values);            if (error != null) {                out.append("error ").append(error).append('\n');            } else {                for (int i = 0; i < p; i++) out.append(i > 0 ? " " : "").append(values[i]);                out.append('\n');            }        }        System.out.print(out);    }}
C#Main.cs · 76 lines
using System;using System.Collections.Generic;using System.Text; class Program{    static List<string> names = new List<string>();    static List<int?> defaultValue = new List<int?>(); // null = 기본값이 정수가 아님    static List<int> defaultFrom = new List<int>();    // -1 = 앞 매개변수를 쓰지 않음     // 인자를 매개변수에 맞춰 넣는다. 오류가 없으면 values를 채우고 null을, 있으면 오류 문자열을 돌려준다.    static string Bind(string[] args, int?[] values)    {        int p = names.Count;        int positional = 0;        bool seenNamed = false;        for (int a = 1; a < args.Length; a++)        {            string arg = args[a];            int eq = arg.IndexOf('=');            if (eq >= 0)            {                seenNamed = true;                string name = arg.Substring(0, eq);                int i = names.IndexOf(name);                if (i < 0) return "unknown " + name;                if (values[i].HasValue) return "twice " + name; // 0도 들어간 값이다                values[i] = int.Parse(arg.Substring(eq + 1));            }            else            {                if (seenNamed) return "order";                if (positional == p) return "many";                values[positional++] = int.Parse(arg);            }        }        for (int i = 0; i < p; i++)        {            if (values[i].HasValue) continue;            if (defaultFrom[i] >= 0) values[i] = values[defaultFrom[i]];            else if (defaultValue[i].HasValue) values[i] = defaultValue[i];            else return "missing " + names[i];        }        return null;    }     static void Main()    {        int p = int.Parse(Console.ReadLine().Trim());        for (int i = 0; i < p; i++)        {            string[] parts = Console.ReadLine().Trim().Split(' ');            int? value = null;            int source = -1;            if (parts.Length == 2)            {                if (char.IsLetter(parts[1][0])) source = names.IndexOf(parts[1]);                else value = int.Parse(parts[1]);            }            names.Add(parts[0]);            defaultValue.Add(value);            defaultFrom.Add(source);        }        int q = int.Parse(Console.ReadLine().Trim());        var sb = new StringBuilder();        for (int t = 0; t < q; t++)        {            string[] args = Console.ReadLine().Trim().Split(' ');            var values = new int?[p];            string error = Bind(args, values);            if (error != null) sb.Append("error ").Append(error).Append('\n');            else sb.Append(string.Join(" ", values)).Append('\n');        }        Console.Write(sb);    }}
C++main.cpp · 88 lines
#include <algorithm>#include <cctype>#include <iostream>#include <optional>#include <sstream>#include <string>#include <vector>using namespace std; struct Param {    string name;    optional<int> value; // 기본값이 정수일 때만 들어 있다    int from = -1;       // 기본값이 앞 매개변수의 값이면 그 자리}; // 인자를 매개변수에 맞춰 넣는다. 오류가 없으면 values를 채우고 빈 문자열을, 있으면 오류 문자열을 돌려준다.string bindArgs(const vector<Param>& params, const vector<string>& args, vector<int>& values) {    int p = (int)params.size();    vector<optional<int>> slot(p); // 비어 있음 = 아직 값이 들어가지 않음(0도 들어간 값이다)    int positional = 0;    bool seenNamed = false;    for (const string& arg : args) {        size_t eq = arg.find('=');        if (eq != string::npos) {            seenNamed = true;            string name = arg.substr(0, eq);            auto it = find_if(params.begin(), params.end(), [&](const Param& x) { return x.name == name; });            if (it == params.end()) return "unknown " + name;            int i = (int)(it - params.begin());            if (slot[i].has_value()) return "twice " + name;            slot[i] = stoi(arg.substr(eq + 1));        } else {            if (seenNamed) return "order";            if (positional == p) return "many";            slot[positional++] = stoi(arg);        }    }    values.assign(p, 0);    for (int i = 0; i < p; i++) {        if (slot[i].has_value()) values[i] = *slot[i];        else if (params[i].from >= 0) values[i] = values[params[i].from];        else if (params[i].value.has_value()) values[i] = *params[i].value;        else return "missing " + params[i].name;    }    return "";} int main() {    string line;    getline(cin, line);    int p = stoi(line);    vector<Param> params;    for (int i = 0; i < p; i++) {        getline(cin, line);        istringstream in(line);        Param x;        string second;        in >> x.name;        if (in >> second) {            if (isalpha((unsigned char)second[0])) {                for (int j = 0; j < i; j++)                    if (params[j].name == second) x.from = j;            } else {                x.value = stoi(second);            }        }        params.push_back(x);    }    getline(cin, line);    int q = stoi(line);    for (int t = 0; t < q; t++) {        getline(cin, line);        istringstream in(line);        string word;        in >> word; // call        vector<string> args;        while (in >> word) args.push_back(word);        vector<int> values;        string error = bindArgs(params, args, values);        if (!error.empty()) {            cout << "error " << error << "\n";        } else {            for (int i = 0; i < p; i++) cout << (i ? " " : "") << values[i];            cout << "\n";        }    }    return 0;}
Cmain.c · 88 lines
#include <ctype.h>#include <stdbool.h>#include <stdio.h>#include <stdlib.h>#include <string.h> #define MAXP 8 static int p;static char names[MAXP][16];static bool has_default[MAXP]; /* 기본값이 정수인가 */static int default_value[MAXP];static int default_from[MAXP]; /* 앞 매개변수의 자리, 없으면 -1 */ static int find_param(const char *name) {    for (int i = 0; i < p; i++)        if (strcmp(names[i], name) == 0) return i;    return -1;} /* 인자를 매개변수에 맞춰 넣는다. 오류가 없으면 values를 채우고 true를,   오류가 있으면 error에 오류 문자열을 쓰고 false를 돌려준다. */static bool bind(char *args, int values[], char *error) {    bool filled[MAXP] = {false}; /* 0도 들어간 값이라 값과 따로 적어 둔다 */    int positional = 0;    bool seen_named = false;    for (char *arg = strtok(args, " \r\n"); arg; arg = strtok(NULL, " \r\n")) {        char *eq = strchr(arg, '=');        if (eq) {            seen_named = true;            *eq = '\0';            int i = find_param(arg);            if (i < 0) { sprintf(error, "unknown %s", arg); return false; }            if (filled[i]) { sprintf(error, "twice %s", arg); return false; }            values[i] = atoi(eq + 1);            filled[i] = true;        } else {            if (seen_named) { strcpy(error, "order"); return false; }            if (positional == p) { strcpy(error, "many"); return false; }            values[positional] = atoi(arg);            filled[positional] = true;            positional++;        }    }    for (int i = 0; i < p; i++) {        if (filled[i]) continue;        if (default_from[i] >= 0) values[i] = values[default_from[i]];        else if (has_default[i]) values[i] = default_value[i];        else { sprintf(error, "missing %s", names[i]); return false; }    }    return true;} int main(void) {    static char line[1024];    if (!fgets(line, sizeof line, stdin)) return 0;    p = atoi(line);    for (int i = 0; i < p; i++) {        char second[32] = "";        if (!fgets(line, sizeof line, stdin)) return 0;        int got = sscanf(line, "%15s %31s", names[i], second);        default_from[i] = -1;        has_default[i] = false;        if (got == 2) {            if (isalpha((unsigned char)second[0])) {                default_from[i] = find_param(second);            } else {                has_default[i] = true;                default_value[i] = atoi(second);            }        }    }    if (!fgets(line, sizeof line, stdin)) return 0;    int q = atoi(line);    for (int t = 0; t < q; t++) {        if (!fgets(line, sizeof line, stdin)) break;        int values[MAXP];        char error[64];        /* 줄 맨 앞의 call은 건너뛴다 */        if (bind(line + 4, values, error)) {            for (int i = 0; i < p; i++) printf(i ? " %d" : "%d", values[i]);            printf("\n");        } else {            printf("error %s\n", error);        }    }    return 0;}
Craykonmain.cray · 92 lines
// 인자를 매개변수에 맞춰 넣는다. 출력할 한 줄(값들 또는 오류)을 돌려준다.맞추기(names, defaultValue, defaultFrom, args){    p = names.Count;    values = NewList(p, null); // 빈값 = 아직 값이 들어가지 않음(0도 들어간 값이다)    positional = 0;    seenNamed = false;    for (a = 1; a < args.Count; a++)    {        arg = args[a];        eq = arg.IndexOf("=");        if (eq >= 0)        {            seenNamed = true;            name = arg.Substring(0, eq);            i = names.IndexOf(name);            if (i < 0)            {                return "error " + "unknown " + name;            }            if (values[i] != null)            {                return "error " + "twice " + name;            }            values[i] = arg.Substring(eq + 1).ToNumber();        }        else        {            if (seenNamed)            {                return "error " + "order";            }            if (positional == p)            {                return "error " + "many";            }            values[positional] = arg.ToNumber();            positional = positional + 1;        }    }    for (i = 0; i < p; i++)    {        if (values[i] == null)        {            if (defaultFrom[i] >= 0)            {                values[i] = values[defaultFrom[i]];            }            else if (defaultValue[i] != null)            {                values[i] = defaultValue[i];            }            else            {                return "error " + "missing " + names[i];            }        }    }    return values.Join(" ");} p = Console.ReadLine().ToNumber();names = [];defaultValue = [];defaultFrom = [];for (i = 0; i < p; i++){    parts = Console.ReadLine().Trim().Split(" ");    value = null;    source = -1;    if (parts.Count == 2)    {        첫글자 = parts[1].Substring(0, 1);        if (첫글자 >= "a" && 첫글자 <= "z")        {            source = names.IndexOf(parts[1]);        }        else        {            value = parts[1].ToNumber();        }    }    names.Add(parts[0]);    defaultValue.Add(value);    defaultFrom.Add(source);}q = Console.ReadLine().ToNumber();for (t = 0; t < q; t++){    args = Console.ReadLine().Trim().Split(" ");    Console.WriteLine(맞추기(names, defaultValue, defaultFrom, args));}