ugrás a tartalomhoz

Rekurzió

mahoo · 2019. Jan. 3. (Cs), 22.45
Lenne egy egyszerű feladat: nested tömbben megszámolni egy adott elem gyakoriságát, rekurzív módon.
Nekem van egy megoldásom, de nem igazán tetszik és érdekelne más megoldás.
  1. function countItems(arr, item) {  
  2.   var result = 0;  
  3.   
  4.   (function count(arr, item){  
  5.     for (var i=0; i<arr.length; i++){  
  6.       if (Array.isArray(arr[i])){  
  7.         count(arr[i], item);  
  8.       } else if (arr[i] === item) {  
  9.         result++;  
  10.       }  
  11.     }  
  12.   })(arr, item);  
  13.   
  14.   return result;  
  15. }  
  16.   
  17.   
  18. var arr = [  
  19.     ["banana""strawberry""apple", ["banana""strawberry""apple", ["apple"]], "apple"],   
  20.   "apple",  
  21.   ["banana""strawberry""apple", ["banana""strawberry""apple"]]  
  22. ];  
  23. console.log(countItems(arr, "apple"));  
Ami nem tetszik:
- van benne egy 'for'
- biztos van szebb megoldas :)
 
1

L'art pour L'art

vbence · 2019. Jan. 4. (P), 00.45
Csak a nulladik elemre vizsgálsz, a szkript magát hívja a maradék elemekkel - array_slice($arr,1). Értelme nem sok van, de van benne egy kis funckionális életérzés.

Also.. a külső szkópban lévő counter nem túl szép, miért nem a függvény eredménye?
4

Lehet, hogy felreertelek, de

mahoo · 2019. Jan. 4. (P), 09.10
Lehet, hogy felreertelek, de sztem nem csak 0. elemre vizsgalok. Pl. ha a 0. elem nem tomb, akkor mar a kovetkezo indexet vizsgalom.
Megmutatnad, hogy hogyan tudom elhagyni a kulso szkopban levo valtozot? Koszi!
11

slice

vbence · 2019. Jan. 5. (Szo), 16.37
Erre gondoltam... ha szigorúan elméleti a kérdés. A kód ugyan tail-call optimizálható, ennek ellenére a krómómban out of memoryval elszáll egyillió elemnél.
  1. function cnt(arg, subject) {  
  2.     if (arg.constructor === Array) {  
  3.         return cnt(arg[0], subject) + (arg.length > 1 ? cnt(arg.slice(1), subject) : 0);  
  4.     } else {  
  5.         return arg == subject ? 1 : 0;  
  6.     }  
  7. }  
  8.   
  9. var arr = [    
  10.     ["banana""strawberry""apple", ["banana""strawberry""apple", ["apple"]], "apple"],  
  11.   "apple",  
  12.   ["banana""strawberry""apple", ["banana""strawberry""apple"]]    
  13. ];  
  14.   
  15. console.log(cnt(arr, "apple"));  
12

Nincs már benne TCO: link

inf · 2019. Jan. 5. (Szo), 20.46
Nincs már benne TCO: link
13

Nem követem

vbence · 2019. Jan. 5. (Szo), 22.11
Egy ideje nem követem a JS enginek fejlődését. Csak onnan jövök, hogy 2019-ben egy neyelvben illene :D
14

Hát én inkább

inf · 2019. Jan. 6. (V), 01.11
Hát én inkább visszafejlődésnek hívnám. A legnagyobb gond nem is ez, mert vissza lehet csinálni bármikor, hanem amit a nyelvvel tettek a szabványban. Siralmas... Igazából vegyesek az érzéseim, mert ténylegesen jelen lévő problémákat próbáltak orvosolni, csak a dolog megragadt azon a szinten, hogy megnéztek más nyelveket, aztán ahol találtak egy működő megoldást, azt berántották a js syntax-ba. Pl gond volt, hogy `function(){...}.bind(this)`-t írtál sok helyen, a CoffeScript-ben erre megoldás volt az arrow function: `() => {}`. Fogták, egy az egyben beemelték a js syntax-ba, amitől az ilyen krix-krax teljesen idegen, mert mindent kulcsszavakkal ír le. Ugyanez történt a spread-el és a rest-el is, mindkettő `...` lett. Aztán volt, hogy a C-n nevelkedett embereknek nem tetszett, hogy itt nem block level scoping van, úgyhogy `var` helyett előrántották a `let` és `const` kulcsszavakat és máris az lett, amikor az előző megoldással az ég világon semmi gond nem volt azon kívül, hogy néhányan lusták voltak megtanulni, hogy ez a nyelv más, mint amit megszoktak. Gyakorlatilag most már ott tartunk, hogy az eredeti nyelvből alig maradt valami, és bár világ életemben utáltam a transpiler-eket, lassan elgondolkodok, hogy írok egy sajátot hozzá... Talán az async-await az egyetlen, amire azt mondom, hogy elfogadható, de az sincs teljesen végiggondolva.
2

reduce + closure

Endyl · 2019. Jan. 4. (P), 00.49
  1. function getCounterReducer(search) {  
  2.   return function counterReducer(value, item) {  
  3.     if (Array.isArray(item)) {  
  4.         return item.reduce(counterReducer, value);  
  5.     }  
  6.     else if (search === item) {  
  7.         return ++value;  
  8.     }  
  9.   };  
  10. }  
  11. var count = arr.reduce(getCounterReducer('apple'), 0);  
Bár azt nem értem, mi a baj a for ciklussal (vagy itt használhatnál for of ciklust is).
3

Jó ez így. Modernebb js-nél

inf · 2019. Jan. 4. (P), 09.02
Jó ez így. Modernebb js-nél for-of, amit használnak, akkor nem kell az i++ meg hasonlók bele. Lehet még array.forEach-el, esetleg még array.reduce-al is, azok valamivel lassabbak, ha sok elem van benne. Esetleg még körül lehetne nézni, hogy vannak e direkt erre nested iteratorok, de nem hiszem, hogy lennének, ha meg te magad írod js-ben, akkor az lassabb lesz a fentieknél, és igazi előnyt nem nyújt.

Ha adatbázisban csinálod, akkor ilyesmi ajánlott inkább: http://weblabor.hu/cikkek/hierarchikusadatkezeles1
5

Igen, nem ES6-os megoldasra

mahoo · 2019. Jan. 4. (P), 09.12
Igen, nem ES6-os megoldasra szerettem volna kihegyezni a kerdest.
6

Miert kell ennyire a rekurziv

MadBence · 2019. Jan. 4. (P), 15.06
Miert kell ennyire a rekurziv megoldas?
  1. function count(arr, item) {  
  2.   if (arr === item) return 1;  
  3.   if (!Array.isArray(arr) || arr.length === 0) return 0;  
  4.   return count(arr[0], item) + count(arr.slice(1), item);  
  5. }  
Masik variacio:
  1. function count(arr, item, cnt = 0) {  
  2.   if (arr === item) return cnt + 1;  
  3.   if (!Array.isArray(arr)) return cnt;  
  4.   if (arr.length === 0) return cnt;  
  5.   return count(arr.slice(1), item, count(arr[0], item, cnt));  
  6. }  
Egy sima ciklussal szerintem elegansabb, es olvashatobb:
  1. function count(arr, item) {  
  2.   let cnt = 0;  
  3.   for (const el of arr) {  
  4.     if (el === item) cnt++;  
  5.     if (Array.isArray(el)) cnt += count(el, item);  
  6.   }  
  7.   return cnt;  
  8. }  
Ha nagyon funkcionalis megkozelitesre van szukseg:
  1. const count = (arr, item) => arr.reduce((cnt, el) => (el === item ? 1 : Array.isArray(el) ? count(el, item) : 0) + cnt, 0);  
Persze inkabb erdemes reszproblemakra szetszedni, es ugy megoldani:
  1. const flatten = arr => arr.reduce((arr, el) => Array.isArray(el) ? arr.concat(flatten(el)) : arr.concat(el), []);  
  2. const count = (arr, item) => flatten(arr).filter(el => el === item).length;  
7

Hat erre gondoltam, nagyon

mahoo · 2019. Jan. 4. (P), 21.21
Hat erre gondoltam, nagyon koszi!
Szerintem ezek sokkal szebb megoldasok mint az enyem...
8

A lényeg szempontjából

inf · 2019. Jan. 5. (Szo), 08.36
A lényeg szempontjából tökmindegy. Működik és érthető ránézésre, nagyjából ennyi számít.
9

Persze, tudom, egyszeruen

mahoo · 2019. Jan. 5. (Szo), 09.28
Persze, tudom, egyszeruen csak kivancsi voltam tovabbi megoldasokra.
Teszem hozza, hogy a 3. az, amit leginkabb hasznalnek, az elso ketto sokkal idoigenyesebb (is), de latni szerettem volna, hogyan lehet meg megcsinalni.
10

Ott egy if-else szerencsésebb

inf · 2019. Jan. 5. (Szo), 10.59
Ott egy if-else szerencsésebb lenne, mert feleslegesen bejárja a keresett elemet is, ha tömböt keresel a tömbben. Egyébként ha nincs biztosítva, hogy hierarchiáról van szó, akkor kellene valami circular graph protection bele, mert különben simán végtelen ciklusba mehet. Ez nagyjából annyi, hogy csinálsz egy Set-et, hogy milyen tömbök voltak már a bejárás során, aztán ha valamelyikkel újra találkozol, akkor kivételt dobsz.
15

For

Hidvégi Gábor · 2019. Jan. 7. (H), 18.38
Ami nem tetszik:
- van benne egy 'for'
Mi a baj a for-ral?
16

Semmi. Nekem van olyan

mahoo · 2019. Jan. 7. (H), 20.51
Semmi. Nekem van olyan informacio ragadasom, hogy rekurzioban nem iteralunk. De ugy nez ki tevesen...
18

Úgy látszik másnak is volt

mahoo · 2019. Jan. 7. (H), 22.00
Úgy látszik másnak is volt ilyen beidegződése :). Köszi!