How to to filter an array of 1 depth nested object efficiently

Viewed 42

I have an array of data that look like this, some of them are group type and contain children like standalone type

const myArray = [{
  name: "Bitcoin",
  balance: 10,
}, {
  name: "ETH",
  tokens: [{
    name: "Ethereum",
    balance: 0,
  }, {
    name: "Chainlink",
    balance: 5,
  }],
}, {
  name: "Solona",
  balance: 0,
}];

I want to make a search and filter tag such as the balance. I have achieved it with this approach.

const searchString = "";
const hideZeroBalanceAsset = false;

const filterGroupToken = (groupToken) => {
  const shallowCopy = { ...groupToken };
  if (searchString) {
    const isGroupNameMatchedSearch = shallowCopy.name
      .toLowerCase()
      .includes(searchString);
    const subTokensMatchedSearch = shallowCopy.tokens.filter((subToken) =>
      subToken.name.toLowerCase().includes(searchString)
    );
    if (subTokensMatchedSearch.length === 0 && !isGroupNameMatchedSearch)
      return undefined;
    if (
      subTokensMatchedSearch.length > 0 &&
      (subTokensMatchedSearch, length < shallowCopy.tokens.length)
    ) {
      shallowCopy.tokens = subTokensMatchedSearch;
    }
  }
  if (hideZeroBalanceAsset) {
    const subTokensNonZeroBalance = shallowCopy.tokens.filter(
      (subToken) => subToken.balance > 0
    );
    if (subTokensNonZeroBalance.length === 0) return undefined;
    if (
      subTokensNonZeroBalance.length > 0 &&
      subTokensNonZeroBalance.length < shallowCopy.tokens.length
    ) {
      shallowCopy.tokens = subTokensNonZeroBalance;
    }
  }
  return shallowCopy;
};

const filterSingleToken = (token) => {
  if (searchString) {
    if (!token.name.toLowerCase().includes(searchString)) return undefined;
  }
  if (hideZeroBalanceAsset) {
    if (token.balance === 0) return undefined;
  }
  return token;
};

const findMatchedTokensReducer = (matchedTokens, nextToken) => {
  if (Array.isArray(nextToken.tokens)) {
    const nextMatchedToken = filterGroupToken(nextToken);
    if (nextMatchedToken) matchedTokens.push(nextMatchedToken);
  } else {
    const nextMatchedToken = filterSingleToken(nextToken);
    if (nextMatchedToken) matchedTokens.push(nextMatchedToken);
  }
  return matchedTokens;
};

const myArray = [{
  name: "Bitcoin",
  balance: 10,
}, {
  name: "ETH",
  tokens: [{
    name: "Ethereum",
    balance: 0,
  }, {
    name: "Chainlink",
    balance: 5,
  }],
}, {
  name: "Solona",
  balance: 0,
}];
const filteredArray = myArray.reduce(findMatchedTokensReducer, []);

console.log({ filteredArray });
.as-console-wrapper { min-height: 100%!important; top: 0; }

However I feel this implementation bloated and inefficiently. Especially, the filterGroupToken function but because I want to show all the children of the group type when the search string matches its name.

1 Answers

Well, I think this can help you with you problem of sorting.

const myArray = [
  {
    name: "Bitcoin",
    balance: 10,
  },
  {
    name: "ETH",
    tokens: [
      {
        name: "Ethereum",
        balance: 0,
      },
      {
        name: "Chainlink",
        balance: 5,
      },
    ],
  },
  {
    name: "Solona",
    balance: 0,
  },
];

const filter = {name: "ETH", subName: "Ethereum"}

let filteredData = myArray.find((money) => money.name === filter.name)

const hasSubValues = filteredData.tokens && filteredData.tokens.length > 0 && filter.subName !== undefined

if(hasSubValues){
    filteredData = filteredData.tokens.find((m) => {
        return m.name === filter.subName
    })
}

console.log(filteredData);

Related