Jak usunąć właściwości obiektu z tablicy bez mutacji?

0

Hej

Jak napisać czystą funkcję razem z usunieciem wlasciwosci - delete flattenarr[flattenarr.length - 1].children;. Ja ją mutuję a chce zdestruturyzowac.

let flattenarr = [];
const treetoarr = (flattenarr, tree, i) => {
  tree.map((t, ii) => {
    flattenarr = [
      ...flattenarr,
      { parentId: i, id: ii, name: t.line || t.name },
    ];
    delete flattenarr[flattenarr.length - 1].children;      
    if (t.children) {
      treetoarr(flattenarr, t.children, ++i);
      --i;
    }
    return t;
  });
  return flattenarr;
};
export const tree = {
   name: "John",
  age: 90,
  children: [
    { line: "line" },
    {
      name: "received",
    },
    {
      name: "new",
      children: [
        {
          name: "selected",
          children: [
            {
              name: "postponed",
              children: [
                {
                  name: "removed",
          }
        ]
      }
    ],
  },

  ],
    },
    {
      name: "labels", 
    }
  ],
};
1

możesz po prostu sklonować obiekt przed usunięciem property

flattenarr[flattenarr.length - 1] = {...flattenarr[flattenarr.length - 1]};
delete flattenarr[flattenarr.length - 1].children;

albo użyć sztuczki do klonowania obiektu bez property przez destrukturyzację, wywołanie funkcji na obiekcie i pominięciem parametru:

flattenarr[flattenarr.length - 1] = (({children, ...rest}) => rest)(flattenarr[flattenarr.length - 1]);

powinno zadziałać. jak nie to daj przykład użycia i oczekiwany output bo ciężko dojść o co właściwie chodzi

2
     flattenarr = [
        ...flattenarr,
        { parentId: i, id: ii, name: t.line || t.name },
      ];
      delete flattenarr[flattenarr.length - 1].children;   

niby robisz delete na właściwości children ostatniego elementu, ale ostatnim elementem i tak będzie { parentId: i, id: ii, name: t.line || t.name },, który nie posiada właściwości children, więc bez sensu.

Tym niemniej warto zauważyć ...flattenarr tworzy ci płytką kopię, czyli tablica jest sklonowana, ale w środku ma te same elementy, więc jak robisz:

delete flattenarr[flattenarr.length - 1].children;

to kasujesz właściwość children na istniejącym obiekcie, czyli mutujesz obiekt (który i tak w tym przypadku nie będzie zawierać takiej właściwości)

  const treetoarr = (flattenarr, tree, i) => {
    tree.map((t, ii) => {
      flattenarr = [

Patrzę na ten kod i trochę nie kumam. Jeśli chcesz iść w paradygmat funkcyjny i robić to bez mutacji, to czemu zamiast użyć wartości z funkcji map, to samemu podmieniasz nie tylko tę zmienną, ale też zmienną i?

 flattenarr = [

Tak jak jest to teraz napisane, to równie dobrze mogłoby to być forEach:

  const treetoarr = (flattenarr, tree, i) => {
    tree.forEach((t, ii) => {

ogólnie ten kod to w zasadzie imperatywny kod, gdzie na siłę co chwila kopiujesz bez sensu tablicę ...flattenarr, zamiast zrobić push jak człowiek i używasz metody map, mimo że chodziło ci o forEach

0

hej

chce otrzymac flatten array z drzewiastej struktury z odniesieniami do rodzica w id, bez hierarchii rodzic dziecko, chce zeby to byla "pure function" bez instrukcji push...

0

Jak chcesz bez pusha to zrób po prostu map i concat na rekurencyjnym wywołaniu - concat zrobi automatycznie flat na argumentach.
Ale gdzie tu w tym wszystkim usuwanie propertiesa?

0
obscurity napisał(a):

Jak chcesz bez pusha to zrób po prostu map i concat na rekurencyjnym wywołaniu - concat zrobi automatycznie flat na argumentach.
Ale gdzie tu w tym wszystkim usuwanie propertiesa?

Z .concat() to będzie pure? Potrafię tylko tak, ale nie działa rekurencyjne wywołanie, co tu poprawić?

let flattenarr = [];
const treetoarr = (flattenarr, tree, i) => { 
  tree.map((t, ii) => {
    flattenarr.concat({ parentId: i, id: ii, name: t.line || t.name });
    if (t.children) {
      treetoarr(flattenarr, t.children, ++i);
      --i;
    }
    return t
  });
  return flattenarr;
};
0
artur2015 napisał(a):
obscurity napisał(a):

Jak chcesz bez pusha to zrób po prostu map i concat na rekurencyjnym wywołaniu - concat zrobi automatycznie flat na argumentach.
Ale gdzie tu w tym wszystkim usuwanie propertiesa?

Z .concat() to będzie pure? Potrafię tylko tak, ale nie działa rekurencyjne wywołanie, co tu poprawić?

z concat to będzie pure. Nie będzie pure jak będziesz przyjmować tablicę i do niej coś dodawał.
Ale z concat jednak nie zadziała bo trzeba by było użyć .concat(...children.map(...)) i o ile by to działało dla małej ilości elementów to trzeba uważać bo przekazywanie argumentów przez foo(...params) przekazuje wszystkie params jako osobne parametry i ładuje je wszystkie na stos - przy dużej ilości dzieci wyprodukuje to Maximum call stack size exceeded

Możesz to zrobić na przykład tak:

const treetoarr = (children, i) =>
  children?.length
    ? children.flatMap((t, ii) => [
        { parentId: i, id: ii, name: t.line || t.name },
        ...treetoarr(t.children, i + 1)
      ])
    : [];
treetoarr(tree.children, 0);

/*
treetoarr(tree.children, 0);
(7) [{…}, {…}, {…}, {…}, {…}, {…}, {…}]
0
: 
{parentId: 0, id: 0, name: 'line'}
1
: 
{parentId: 0, id: 1, name: 'received'}
2
: 
{parentId: 0, id: 2, name: 'new'}
3
: 
{parentId: 1, id: 0, name: 'selected'}
4
: 
{parentId: 2, id: 0, name: 'postponed'}
5
: 
{parentId: 3, id: 0, name: 'removed'}
6
: 
{parentId: 0, id: 3, name: 'labels'}
*/

ale masz też błąd w nadawaniu idków elementom, jeśli będzie wiele dzieci to ich wszystkie "wnuki" dostaną takie samo parentId.

0

Wielkie dzieki! o to wlasnie mi chodzilo, chociaz z przygnebieniem zauwazam ze takiej funkcji z glowy nie potrafie napisac... Jak doszedles do takiej wprawy, ze piszesz te funkcje na zawolanie ?

0
artur2015 napisał(a):

hej

chce otrzymac flatten array z drzewiastej struktury z odniesieniami do rodzica w id, bez hierarchii rodzic dziecko, chce zeby to byla "pure function" bez instrukcji push...

Rzecz w tym, że to nie kwestia pusha, tylko tego czy w swojej funkcji mutujesz coś z zewnątrz. Pomijając już kwestię, czy mutowałeś coś niechcący w środku (swoją drogą JS to słaby język do programowania funkcyjnego, , to wersja z twojego pierwszego posta w samych założeniach nie była "pure function", ponieważ mutowałeś zmienną globalną flattenarr:

let flattenarr = [];
const treetoarr = (flattenarr, tree, i) => {
 tree.map((t, ii) => {
   flattenarr = [

Z drugiej strony może istnieć czysta funkcja, która będzie mieć push w środku. Zobacz na funkcję treetoarr zaimplementowaną tak:

const treetoarr = (tree) => { 
  const flattenarr = []; // nowiutka tablica
  const withoutChildren = ({children, ...rest}) => ({...rest}); // kopiujemy obiekt bez children

  // pomocnicza funkcja rekurencyjna (która jest imperatywna/nie czysta)
  // bo mutuje tablicę flattenarr, ale co z tego,
  // skoro nie wychodzi to poza granice funkcji treetoarr
  function flatten(node) { 
      flattenarr.push(withoutChildren(node)); // dodajemy do nowiutkiej tablicy
      (node.children || []).forEach(flatten); // iterujemy w głąb (rekurencja)
  }
  flatten(tree);
  return flattenarr; // zwracamy nowiutką tablicę
};

I też można ją nazwać czystą, bo sama sobie tworzy tablicę flattenarr i robi na niej push, ale przecież to jej własna tablica. Chodzi o to, że ten push to będzie tutaj tylko szczegół implementacyjny (funkcja w środku ma imperatywny kod, ale i tak jest czysta, bo nic nie mutuje tj: wyobraź sobie takie dwie funkcje:

const foo = arg => {
   return ["Hello"].concat("World");
};
const bar = arg => {
   const tmp = [];
   tmp.push("Hello");
   tmp.push("World");
   return tmp;
};

czy jest między nimi jakaś wielka różnica? No nie. Poza tym, że używają innych funkcji, to obie można uznać za czyste. Druga używa push, ale co z tego, skoro robi to na tablicy, którą sama tworzy.

Nie ma co wpadać w cargo cult - czyste funkcje nie polegają na tym, żeby wrzucać map, concat i reduce czy ... bez pomyślenia, bo ktoś tak powiedział, że push jest złe.

Nie mówię oczywiście, że push nigdy się nie kłóci z czystymi funkcjami, tylko żeby spojrzeć na to w ten sposób, że czysta funkcja to jest to https://en.wikipedia.org/wiki/Pure_function a nie zakaz używania pewnych funkcji.

1

LukeJL Dzieki!!

1 użytkowników online, w tym zalogowanych: 0, gości: 1