33-bo'lim: Funksional dasturlash¶
Funksional dasturlash (functional programming) β funksiyalarni qiymat sifatida uzatish, ularni birlashtirish va o'zgarmas (immutable) ma'lumotlar ustida ishlashga asoslangan uslub. Bu bo'limda compose/pipe, curry, memoize kabi yuqori tartibli (higher-order) funksiyalar va map/filter/reduce kabi klassik kombinatorlar qo'lda yoziladi. Maqsad β kutubxonadan foydalanish emas, balki bu abstraksiyalar ichkaridan qanday ishlashini tushunish. Kod JS, PHP va Python tillarida idiomatik ko'rinishda beriladi; generator/lazy mavzularida JS va Python yetarli.
697. compose (funksiyalarni o'ngdan birlashtirish)¶
Bir nechta funksiyani birlashtiradi: oxirgisi birinchi ishlaydi, natijasi keyingisiga uzatiladi.
β± O(n) Β· πΎ O(n)
JS
const compose = (...fns) => (x) =>
fns.reduceRight((acc, f) => f(acc), x);
// compose(x => x + 1, x => x * 2)(5) // 11
function compose(callable ...$fns): callable {
return fn($x) => array_reduce(
array_reverse($fns),
fn($acc, $f) => $f($acc),
$x
);
}
// compose(fn($x) => $x + 1, fn($x) => $x * 2)(5) // 11
from functools import reduce
def compose(*fns):
return lambda x: reduce(lambda acc, f: f(acc), reversed(fns), x)
# compose(lambda x: x + 1, lambda x: x * 2)(5) # 11
698. pipe (funksiyalarni chapdan birlashtirish)¶
compose'ning teskarisi: funksiyalar yozilgan tartibda chapdan o'ngga qo'llanadi.
β± O(n) Β· πΎ O(n)
JS
const pipe = (...fns) => (x) =>
fns.reduce((acc, f) => f(acc), x);
// pipe(x => x + 1, x => x * 2)(5) // 12
function pipe(callable ...$fns): callable {
return fn($x) => array_reduce($fns, fn($acc, $f) => $f($acc), $x);
}
// pipe(fn($x) => $x + 1, fn($x) => $x * 2)(5) // 12
from functools import reduce
def pipe(*fns):
return lambda x: reduce(lambda acc, f: f(acc), fns, x)
# pipe(lambda x: x + 1, lambda x: x * 2)(5) # 12
699. curry (argumentlarni bo'lib uzatish)¶
Ko'p argumentli funksiyani har biri bitta argument oluvchi funksiyalar zanjiriga aylantiradi.
JS
const curry = (fn) => {
const helper = (...args) =>
args.length >= fn.length
? fn(...args)
: (...more) => helper(...args, ...more);
return helper;
};
const add = curry((a, b, c) => a + b + c);
// add(1)(2)(3) // 6 ; add(1, 2)(3) // 6
function curry(callable $fn, int $arity): callable {
$helper = function (array $args) use (&$helper, $fn, $arity) {
if (count($args) >= $arity) {
return $fn(...$args);
}
return fn(...$more) => $helper([...$args, ...$more]);
};
return fn(...$args) => $helper($args);
}
$add = curry(fn($a, $b, $c) => $a + $b + $c, 3);
// $add(1)(2)(3) // 6
def curry(fn, arity):
def helper(args):
if len(args) >= arity:
return fn(*args)
return lambda *more: helper(args + list(more))
return lambda *args: helper(list(args))
add = curry(lambda a, b, c: a + b + c, 3)
# add(1)(2)(3) # 6
700. partial application (qisman qo'llash)¶
Funksiyaning ba'zi argumentlarini oldindan biriktirib, qolganini keyin qabul qiluvchi yangi funksiya yaratadi.
JS
const partial = (fn, ...preset) =>
(...rest) => fn(...preset, ...rest);
const greet = (greeting, name) => `${greeting}, ${name}!`;
const hello = partial(greet, "Salom");
// hello("Olim") // "Salom, Olim!"
function partial(callable $fn, ...$preset): callable {
return fn(...$rest) => $fn(...$preset, ...$rest);
}
$greet = fn($g, $name) => "$g, $name!";
$hello = partial($greet, "Salom");
// $hello("Olim") // "Salom, Olim!"
def partial(fn, *preset):
return lambda *rest: fn(*preset, *rest)
greet = lambda g, name: f"{g}, {name}!"
hello = partial(greet, "Salom")
# hello("Olim") # "Salom, Olim!"
701. memoize (natijalarni keshlash)¶
Funksiya natijalarini argumentlar bo'yicha keshda saqlaydi; takror chaqiruvda hisoblamay keshdan qaytaradi.
β± chaqiruv O(1) (keshda) Β· πΎ O(noyob argumentlar)
JS
const memoize = (fn) => {
const cache = new Map();
return (...args) => {
const key = JSON.stringify(args);
if (cache.has(key)) return cache.get(key);
const result = fn(...args);
cache.set(key, result);
return result;
};
};
// const slow = memoize(n => n * n); slow(4) // 16 (ikkinchi chaqiruv keshdan)
function memoize(callable $fn): callable {
$cache = [];
return function (...$args) use (&$cache, $fn) {
$key = serialize($args);
if (!array_key_exists($key, $cache)) {
$cache[$key] = $fn(...$args);
}
return $cache[$key];
};
}
// $slow = memoize(fn($n) => $n * $n); $slow(4) // 16
def memoize(fn):
cache = {}
def wrapper(*args):
if args not in cache:
cache[args] = fn(*args)
return cache[args]
return wrapper
# slow = memoize(lambda n: n * n); slow(4) # 16
702. once (faqat bir marta ishlaydigan funksiya)¶
Funksiyani faqat birinchi chaqiruvda bajaradi; keyingi chaqiruvlarda saqlangan natijani qaytaradi.
JS
const once = (fn) => {
let called = false, result;
return (...args) => {
if (!called) { called = true; result = fn(...args); }
return result;
};
};
// const init = once(() => Math.random()); init() === init() // true
function once(callable $fn): callable {
$called = false;
$result = null;
return function (...$args) use (&$called, &$result, $fn) {
if (!$called) { $called = true; $result = $fn(...$args); }
return $result;
};
}
// $init = once(fn() => mt_rand()); $init() === $init() // true
def once(fn):
state = {"called": False, "result": None}
def wrapper(*args):
if not state["called"]:
state["called"] = True
state["result"] = fn(*args)
return state["result"]
return wrapper
# init = once(lambda: __import__("random").random()); init() == init() # True
703. map (qo'lda)¶
Har bir elementga funksiyani qo'llab, yangi ro'yxat yasaydi (kutubxonasiz).
β± O(n) Β· πΎ O(n)
JS
const map = (fn, arr) => {
const out = [];
for (const v of arr) out.push(fn(v));
return out;
};
// map(x => x * 2, [1, 2, 3]) // [2, 4, 6]
function mymap(callable $fn, array $arr): array {
$out = [];
foreach ($arr as $v) $out[] = $fn($v);
return $out;
}
// mymap(fn($x) => $x * 2, [1, 2, 3]) // [2, 4, 6]
def my_map(fn, arr):
out = []
for v in arr:
out.append(fn(v))
return out
# my_map(lambda x: x * 2, [1, 2, 3]) # [2, 4, 6]
704. filter (qo'lda)¶
Shartni (predikatni) qanoatlantiruvchi elementlarni saqlab qoladi.
β± O(n) Β· πΎ O(n)
JS
const filter = (pred, arr) => {
const out = [];
for (const v of arr) if (pred(v)) out.push(v);
return out;
};
// filter(x => x % 2 === 0, [1, 2, 3, 4]) // [2, 4]
function myfilter(callable $pred, array $arr): array {
$out = [];
foreach ($arr as $v) if ($pred($v)) $out[] = $v;
return $out;
}
// myfilter(fn($x) => $x % 2 === 0, [1, 2, 3, 4]) // [2, 4]
def my_filter(pred, arr):
out = []
for v in arr:
if pred(v):
out.append(v)
return out
# my_filter(lambda x: x % 2 == 0, [1, 2, 3, 4]) # [2, 4]
705. reduce (qo'lda)¶
Ro'yxatni boshlang'ich qiymatdan boshlab bitta natijaga yig'adi (fold).
β± O(n) Β· πΎ O(1)
JS
const reduce = (fn, init, arr) => {
let acc = init;
for (const v of arr) acc = fn(acc, v);
return acc;
};
// reduce((a, b) => a + b, 0, [1, 2, 3, 4]) // 10
function myreduce(callable $fn, $init, array $arr) {
$acc = $init;
foreach ($arr as $v) $acc = $fn($acc, $v);
return $acc;
}
// myreduce(fn($a, $b) => $a + $b, 0, [1, 2, 3, 4]) // 10
def my_reduce(fn, init, arr):
acc = init
for v in arr:
acc = fn(acc, v)
return acc
# my_reduce(lambda a, b: a + b, 0, [1, 2, 3, 4]) # 10
706. flatMap (map + bitta darajaga yassilash)¶
Har bir elementga funksiyani qo'llaydi, natija ro'yxatlarini bitta tekis ro'yxatga qo'shadi.
β± O(n) Β· πΎ O(n)
JS
const flatMap = (fn, arr) =>
arr.reduce((acc, v) => acc.concat(fn(v)), []);
// flatMap(x => [x, x * 10], [1, 2]) // [1, 10, 2, 20]
function flatMap(callable $fn, array $arr): array {
$out = [];
foreach ($arr as $v) {
foreach ((array) $fn($v) as $u) $out[] = $u;
}
return $out;
}
// flatMap(fn($x) => [$x, $x * 10], [1, 2]) // [1, 10, 2, 20]
def flat_map(fn, arr):
out = []
for v in arr:
out.extend(fn(v))
return out
# flat_map(lambda x: [x, x * 10], [1, 2]) # [1, 10, 2, 20]
707. zip (ikki ro'yxatni juftlash)¶
Ikki (yoki undan ko'p) ro'yxatni element-element juftlab, juftliklar ro'yxatini qaytaradi.
β± O(n) Β· πΎ O(n)
JS
const zip = (a, b) => {
const n = Math.min(a.length, b.length);
const out = [];
for (let i = 0; i < n; i++) out.push([a[i], b[i]]);
return out;
};
// zip([1, 2, 3], ["a", "b"]) // [[1,"a"],[2,"b"]]
function zip(array $a, array $b): array {
$n = min(count($a), count($b));
$out = [];
for ($i = 0; $i < $n; $i++) $out[] = [$a[$i], $b[$i]];
return $out;
}
// zip([1, 2, 3], ["a", "b"]) // [[1,"a"],[2,"b"]]
def my_zip(a, b):
return [(a[i], b[i]) for i in range(min(len(a), len(b)))]
# my_zip([1, 2, 3], ["a", "b"]) # [(1,"a"),(2,"b")]
708. unzip (juftliklarni ikki ro'yxatga ajratish)¶
zip'ning teskarisi: juftliklar ro'yxatini ikkita alohida ro'yxatga ajratadi.
β± O(n) Β· πΎ O(n)
JS
const unzip = (pairs) => {
const a = [], b = [];
for (const [x, y] of pairs) { a.push(x); b.push(y); }
return [a, b];
};
// unzip([[1,"a"],[2,"b"]]) // [[1,2],["a","b"]]
function unzip(array $pairs): array {
$a = []; $b = [];
foreach ($pairs as [$x, $y]) { $a[] = $x; $b[] = $y; }
return [$a, $b];
}
// unzip([[1,"a"],[2,"b"]]) // [[1,2],["a","b"]]
def unzip(pairs):
a, b = [], []
for x, y in pairs:
a.append(x)
b.append(y)
return a, b
# unzip([(1,"a"),(2,"b")]) # ([1,2],["a","b"])
709. groupBy (kalit bo'yicha guruhlash)¶
Har bir elementdan kalit hisoblab, shu kalit ostidagi ro'yxatlarga to'playdi.
β± O(n) Β· πΎ O(n)
JS
const groupBy = (keyFn, arr) => {
const out = {};
for (const v of arr) {
const k = keyFn(v);
(out[k] ??= []).push(v);
}
return out;
};
// groupBy(x => x % 2, [1, 2, 3, 4]) // {1:[1,3], 0:[2,4]}
function groupBy(callable $keyFn, array $arr): array {
$out = [];
foreach ($arr as $v) $out[$keyFn($v)][] = $v;
return $out;
}
// groupBy(fn($x) => $x % 2, [1, 2, 3, 4]) // [1=>[1,3], 0=>[2,4]]
def group_by(key_fn, arr):
out = {}
for v in arr:
out.setdefault(key_fn(v), []).append(v)
return out
# group_by(lambda x: x % 2, [1, 2, 3, 4]) # {1:[1,3], 0:[2,4]}
710. partition (shartga ko'ra ikkiga bo'lish)¶
Ro'yxatni predikat bo'yicha ikkiga ajratadi: rost va yolg'on bo'lganlar.
β± O(n) Β· πΎ O(n)
JS
const partition = (pred, arr) => {
const yes = [], no = [];
for (const v of arr) (pred(v) ? yes : no).push(v);
return [yes, no];
};
// partition(x => x > 2, [1, 2, 3, 4]) // [[3,4],[1,2]]
function partition(callable $pred, array $arr): array {
$yes = []; $no = [];
foreach ($arr as $v) {
if ($pred($v)) $yes[] = $v; else $no[] = $v;
}
return [$yes, $no];
}
// partition(fn($x) => $x > 2, [1, 2, 3, 4]) // [[3,4],[1,2]]
def partition(pred, arr):
yes, no = [], []
for v in arr:
(yes if pred(v) else no).append(v)
return yes, no
# partition(lambda x: x > 2, [1, 2, 3, 4]) # ([3,4],[1,2])
711. chunk (bo'laklarga bo'lish)¶
Ro'yxatni belgilangan o'lchamli ketma-ket bo'laklarga ajratadi.
β± O(n) Β· πΎ O(n)
JS
const chunk = (size, arr) => {
const out = [];
for (let i = 0; i < arr.length; i += size)
out.push(arr.slice(i, i + size));
return out;
};
// chunk(2, [1, 2, 3, 4, 5]) // [[1,2],[3,4],[5]]
function chunk(int $size, array $arr): array {
$out = [];
for ($i = 0; $i < count($arr); $i += $size)
$out[] = array_slice($arr, $i, $size);
return $out;
}
// chunk(2, [1, 2, 3, 4, 5]) // [[1,2],[3,4],[5]]
def chunk(size, arr):
return [arr[i:i + size] for i in range(0, len(arr), size)]
# chunk(2, [1, 2, 3, 4, 5]) # [[1,2],[3,4],[5]]
712. deep flatten (chuqur yassilash)¶
Ixtiyoriy chuqurlikdagi ichma-ich ro'yxatlarni bitta tekis ro'yxatga aylantiradi.
β± O(n) Β· πΎ O(n)
JS
const deepFlatten = (arr) =>
arr.reduce(
(acc, v) => acc.concat(Array.isArray(v) ? deepFlatten(v) : v),
[]
);
// deepFlatten([1, [2, [3, [4]]], 5]) // [1, 2, 3, 4, 5]
function deepFlatten(array $arr): array {
$out = [];
foreach ($arr as $v) {
if (is_array($v)) {
foreach (deepFlatten($v) as $u) $out[] = $u;
} else {
$out[] = $v;
}
}
return $out;
}
// deepFlatten([1, [2, [3, [4]]], 5]) // [1, 2, 3, 4, 5]
def deep_flatten(arr):
out = []
for v in arr:
if isinstance(v, list):
out.extend(deep_flatten(v))
else:
out.append(v)
return out
# deep_flatten([1, [2, [3, [4]]], 5]) # [1, 2, 3, 4, 5]
713. pluck (xossani ajratish)¶
Obyektlar ro'yxatidan berilgan xossa (key) qiymatlarini yig'ib oladi.
β± O(n) Β· πΎ O(n)
JS
const pluck = (key, arr) => arr.map((o) => o[key]);
// pluck("name", [{name: "Olim"}, {name: "Vali"}]) // ["Olim", "Vali"]
function pluck(string $key, array $arr): array {
return array_map(fn($o) => $o[$key], $arr);
}
// pluck("name", [["name" => "Olim"], ["name" => "Vali"]]) // ["Olim", "Vali"]
def pluck(key, arr):
return [o[key] for o in arr]
# pluck("name", [{"name": "Olim"}, {"name": "Vali"}]) # ["Olim", "Vali"]
714. path getter (yo'l bo'yicha qiymat olish)¶
Ichma-ich strukturadan kalitlar yo'li bo'yicha qiymatni oladi; topilmasa standart qiymat qaytaradi.
β± O(k) Β· πΎ O(1)
JS
const getPath = (obj, path, def = undefined) => {
let cur = obj;
for (const key of path) {
if (cur == null || !(key in cur)) return def;
cur = cur[key];
}
return cur;
};
// getPath({a: {b: {c: 7}}}, ["a", "b", "c"]) // 7
function getPath(array $obj, array $path, $def = null) {
$cur = $obj;
foreach ($path as $key) {
if (!is_array($cur) || !array_key_exists($key, $cur)) return $def;
$cur = $cur[$key];
}
return $cur;
}
// getPath(["a" => ["b" => ["c" => 7]]], ["a", "b", "c"]) // 7
def get_path(obj, path, default=None):
cur = obj
for key in path:
if not isinstance(cur, dict) or key not in cur:
return default
cur = cur[key]
return cur
# get_path({"a": {"b": {"c": 7}}}, ["a", "b", "c"]) # 7
715. negate / complement (predikatni teskarilash)¶
Predikatni qabul qilib, uning natijasini teskari qiluvchi yangi predikat qaytaradi.
JS
const negate = (pred) => (...args) => !pred(...args);
const isEven = (n) => n % 2 === 0;
const isOdd = negate(isEven);
// isOdd(3) // true
function negate(callable $pred): callable {
return fn(...$args) => !$pred(...$args);
}
$isEven = fn($n) => $n % 2 === 0;
$isOdd = negate($isEven);
// $isOdd(3) // true
def negate(pred):
return lambda *args: not pred(*args)
is_even = lambda n: n % 2 == 0
is_odd = negate(is_even)
# is_odd(3) # True
716. tap (oraliq nazorat)¶
Qiymatni o'zgartirmasdan unga funksiyani (masalan, log) qo'llaydi va qiymatni qaytaradi; zanjirlarda foydali.
JS
const tap = (fn) => (x) => { fn(x); return x; };
// [1, 2, 3].map(x => x * 2).map(tap(console.log)) // log qiladi, [2,4,6] qaytaradi
function tap(callable $fn): callable {
return function ($x) use ($fn) { $fn($x); return $x; };
}
// $log = tap(fn($x) => fwrite(STDERR, $x . "\n")); $log(5) // 5
def tap(fn):
def wrapper(x):
fn(x)
return x
return wrapper
# tap(print)(5) # 5 (va ekranga 5 chiqadi)
717. identity / constant¶
identity argumentni o'zini qaytaradi; constant esa har doim bitta o'zgarmas qiymatni qaytaruvchi funksiya yasaydi.
JS
const identity = (x) => x;
const constant = (x) => () => x;
// identity(5) // 5 ; constant(7)() // 7
function identity($x) { return $x; }
function constant_fn($x): callable { return fn() => $x; }
// identity(5) // 5 ; constant_fn(7)() // 7
718. take / drop (boshidan olish / tashlash)¶
take birinchi n ta elementni oladi; drop birinchi n tasini tashlab, qolganini qaytaradi.
β± O(n) Β· πΎ O(n)
JS
const take = (n, arr) => arr.slice(0, n);
const drop = (n, arr) => arr.slice(n);
// take(2, [1, 2, 3, 4]) // [1, 2] ; drop(2, [1, 2, 3, 4]) // [3, 4]
function take(int $n, array $arr): array {
return array_slice($arr, 0, $n);
}
function drop(int $n, array $arr): array {
return array_slice($arr, $n);
}
// take(2, [1, 2, 3, 4]) // [1, 2] ; drop(2, [1, 2, 3, 4]) // [3, 4]
def take(n, arr):
return arr[:n]
def drop(n, arr):
return arr[n:]
# take(2, [1, 2, 3, 4]) # [1, 2] ; drop(2, [1, 2, 3, 4]) # [3, 4]
719. range (sonlar ketma-ketligi)¶
start dan stop gacha (stop kirmaydi) step qadam bilan sonlar ro'yxatini yasaydi.
β± O(n) Β· πΎ O(n)
JS
const range = (start, stop, step = 1) => {
const out = [];
for (let i = start; step > 0 ? i < stop : i > stop; i += step)
out.push(i);
return out;
};
// range(0, 10, 2) // [0, 2, 4, 6, 8]
function myrange(int $start, int $stop, int $step = 1): array {
$out = [];
for ($i = $start; $step > 0 ? $i < $stop : $i > $stop; $i += $step)
$out[] = $i;
return $out;
}
// myrange(0, 10, 2) // [0, 2, 4, 6, 8]
def my_range(start, stop, step=1):
out = []
i = start
while (i < stop) if step > 0 else (i > stop):
out.append(i)
i += step
return out
# my_range(0, 10, 2) # [0, 2, 4, 6, 8]
720. repeat (qiymatni takrorlash)¶
Berilgan qiymatdan n ta nusxadan iborat ro'yxat yasaydi.
β± O(n) Β· πΎ O(n)
JS
const repeat = (value, n) => Array.from({ length: n }, () => value);
// repeat("x", 3) // ["x", "x", "x"]
function repeat($value, int $n): array {
return array_fill(0, $n, $value);
}
// repeat("x", 3) // ["x", "x", "x"]
721. uniqBy (kalit bo'yicha noyoblash)¶
Har bir elementdan kalit hisoblab, shu kalit birinchi marta uchragan elementlarni saqlaydi.
β± O(n) Β· πΎ O(n)
JS
const uniqBy = (keyFn, arr) => {
const seen = new Set();
const out = [];
for (const v of arr) {
const k = keyFn(v);
if (!seen.has(k)) { seen.add(k); out.push(v); }
}
return out;
};
// uniqBy(x => x % 3, [1, 2, 3, 4, 5]) // [1, 2, 3]
function uniqBy(callable $keyFn, array $arr): array {
$seen = [];
$out = [];
foreach ($arr as $v) {
$k = $keyFn($v);
if (!isset($seen[$k])) { $seen[$k] = true; $out[] = $v; }
}
return $out;
}
// uniqBy(fn($x) => $x % 3, [1, 2, 3, 4, 5]) // [1, 2, 3]
def uniq_by(key_fn, arr):
seen = set()
out = []
for v in arr:
k = key_fn(v)
if k not in seen:
seen.add(k)
out.append(v)
return out
# uniq_by(lambda x: x % 3, [1, 2, 3, 4, 5]) # [1, 2, 3]
722. sortBy (kalit bo'yicha saralash)¶
Har bir elementdan hisoblangan kalit (yoki kalitlar) bo'yicha barqaror saralaydi.
β± O(n log n) Β· πΎ O(n)
JS
const sortBy = (keyFn, arr) =>
[...arr].sort((a, b) => {
const ka = keyFn(a), kb = keyFn(b);
return ka < kb ? -1 : ka > kb ? 1 : 0;
});
// sortBy(s => s.length, ["bbb", "a", "cc"]) // ["a", "cc", "bbb"]
function sortBy(callable $keyFn, array $arr): array {
usort($arr, fn($a, $b) => $keyFn($a) <=> $keyFn($b));
return $arr;
}
// sortBy(fn($s) => strlen($s), ["bbb", "a", "cc"]) // ["a", "cc", "bbb"]
def sort_by(key_fn, arr):
return sorted(arr, key=key_fn)
# sort_by(len, ["bbb", "a", "cc"]) # ["a", "cc", "bbb"]
723. maxBy / minBy (kalit bo'yicha eng katta/kichik)¶
Kalit funksiyasi bo'yicha eng katta yoki eng kichik elementni topadi.
β± O(n) Β· πΎ O(1)
JS
const maxBy = (keyFn, arr) =>
arr.reduce((best, v) => (keyFn(v) > keyFn(best) ? v : best));
const minBy = (keyFn, arr) =>
arr.reduce((best, v) => (keyFn(v) < keyFn(best) ? v : best));
// maxBy(s => s.length, ["a", "ccc", "bb"]) // "ccc"
function maxBy(callable $keyFn, array $arr) {
return array_reduce(
$arr,
fn($best, $v) => ($best === null || $keyFn($v) > $keyFn($best)) ? $v : $best,
null
);
}
function minBy(callable $keyFn, array $arr) {
return array_reduce(
$arr,
fn($best, $v) => ($best === null || $keyFn($v) < $keyFn($best)) ? $v : $best,
null
);
}
// maxBy(fn($s) => strlen($s), ["a", "ccc", "bb"]) // "ccc"
def max_by(key_fn, arr):
return max(arr, key=key_fn)
def min_by(key_fn, arr):
return min(arr, key=key_fn)
# max_by(len, ["a", "ccc", "bb"]) # "ccc"
724. fold / scan (yig'ish va oraliq natijalar)¶
fold reduce kabi bitta natija beradi; scan esa har bir qadamdagi oraliq yig'indilar ro'yxatini qaytaradi.
β± O(n) Β· πΎ O(n)
JS
const scan = (fn, init, arr) => {
const out = [init];
let acc = init;
for (const v of arr) { acc = fn(acc, v); out.push(acc); }
return out;
};
// scan((a, b) => a + b, 0, [1, 2, 3, 4]) // [0, 1, 3, 6, 10]
function scan(callable $fn, $init, array $arr): array {
$out = [$init];
$acc = $init;
foreach ($arr as $v) { $acc = $fn($acc, $v); $out[] = $acc; }
return $out;
}
// scan(fn($a, $b) => $a + $b, 0, [1, 2, 3, 4]) // [0, 1, 3, 6, 10]
def scan(fn, init, arr):
out = [init]
acc = init
for v in arr:
acc = fn(acc, v)
out.append(acc)
return out
# scan(lambda a, b: a + b, 0, [1, 2, 3, 4]) # [0, 1, 3, 6, 10]
725. lazy sequence (generator orqali dangasa ketma-ketlik)¶
Generator yordamida cheksiz yoki katta ketma-ketlikni xotirada to'liq saqlamasdan, talab bo'yicha element-element beradi.
JS
function* naturals() {
let n = 1;
while (true) yield n++;
}
function* take(n, gen) {
let i = 0;
for (const v of gen) {
if (i++ >= n) return;
yield v;
}
}
// [...take(5, naturals())] // [1, 2, 3, 4, 5]
def naturals():
n = 1
while True:
yield n
n += 1
def take(n, gen):
out = []
for v in gen:
if len(out) >= n:
break
out.append(v)
return out
# take(5, naturals()) # [1, 2, 3, 4, 5]
726. frequency / countBy (chastotani sanash)¶
Har bir element (yoki kalit) necha marta uchraganini sanab, kalit-son lug'atini qaytaradi.
β± O(n) Β· πΎ O(n)
JS
const countBy = (keyFn, arr) => {
const out = {};
for (const v of arr) {
const k = keyFn(v);
out[k] = (out[k] ?? 0) + 1;
}
return out;
};
// countBy(x => x % 2, [1, 2, 3, 4, 5]) // {1: 3, 0: 2}