-4

im building an api which needs to find the longest path that matches a number in a very performant manner.

eg

// API Request
{
'number': '123456789'
}

// DATA
[
  {
    'prefix': '1',
    'price': 30.5
  },
{
    'prefix': '123',
    'price': 10.5
  },
{
    'prefix': '12345',
    'price': 22.5
  },
]


// API RESPONSE
{
    'prefix': '12345',
    'price': 22.5
  },

As you can see from above the response should be the row with prefix of 12345 as it is the longest. please i need a bit of help in doing this. i have spent about 2 days now looking for a solution so i decided to come to stack overflow for answers. Thanks in advance!

8
  • Can you share any of your attempts, and explain how they failed or what went wrong? Commented Apr 22, 2022 at 12:56
  • yourData.reduce((longest, current) => { your logic here }, null) Commented Apr 22, 2022 at 13:00
  • What happens if there are two elements with same prefix ie, 12345? If you can mutate the data then please try: data.sort((a, b) => { return a.prefix.length > b.prefix.length ? 1 : -1 })[0];. It's bit more tricky if you are not allowed to mutate data. Please see what this gets you: const longest = data.find(x => x.prefix.length === Math.max(...data.map(y => y.prefix.length))) ;. Let us know how it goes.
    – jsN00b
    Commented Apr 22, 2022 at 13:03
  • @jsN00b i have removed the duplicates from the dataset so it has no duplicates Commented Apr 22, 2022 at 13:08
  • 1
    @jsN00b that will calculate the max and array of lengths many times. Better to break it into two tasks: const max = Math.max(...DATA.map(obj => obj.prefix.length)); then const result = DATA.find(obj => obj.prefix.length === max);
    – Wyck
    Commented Apr 22, 2022 at 13:34

2 Answers 2

0

You could do the following where you check each characters position in the prefix to figure out which data set is the best match.

const incoming = {
  'number': '123456789'
}

const data = [{
    'prefix': '1',
    'price': 30.5
  },
  {
    'prefix': '123',
    'price': 10.5
  },
  {
    'prefix': '12345',
    'price': 22.5
  }
];


let bestMatch = {
  matchSuccess: 0,
  data: data[0]
};
for (let i = 0; i < data.length; i++) {
  let matchSuccess = 0;
  for (var x = 0; x < data[i].prefix.length; x++) {
    const c = data[i].prefix.charAt(x);
    if (data[i].prefix.charAt(x) === incoming.number.charAt(x)) {
      matchSuccess++;
    }
  }
  if (matchSuccess > bestMatch.matchSuccess) {
    bestMatch = {
      matchSuccess,
      data: data[i]
    }
  }
}

console.log(bestMatch);

1
  • hi thanks for the help. but this solution seems to think that the data can only have numbers associated to the prefix but in reality it can be any mix of numbers eg ``` [{'prefix': '123'}, {'prefix': '3'}, {'prefix': '234'} , {'prefix': '765'}, {'prefix': '12'} , {'prefix': '1'}]``` so ill need to find the longest prefix for '123456' in the mix Commented Apr 22, 2022 at 13:44
0

From the above comment ...

"The OP is not looking for ... "the longest possible path from an array of objects" ... which hopefully not only to me means a result like ... 'data[2].prefix' ... for ... const incoming = { prefix: '123456789' }. The OP's provided incoming value even would not match anything due to the number: '123456789' key-value pair (btw. number being a string type) instead of prefix: '123456789' . I highly recommend to edit topic and description of the problem."

But what the OP actually might want is ... filter, from an array of objects, the very first object where any of the object entry's stringified values matches the stringified value of the API call in the longest possible way.

function collectItemOfBestCoveringEntryValue(collector, item) {
  const { search = '', coverage = 0, result = null } = collector;
  if (search !== '') {

    const matchingValues = Object
      // retrieve all of an item's values.
      .values(item)
      // filter any value which matches `search`.
      .filter(value => {

        value = String(value);

        return ((
          value !== ''
        ) && (
          // it might even goe both ways ...
          // ... `value` in `search` ...
          search.includes(value) ||
          // ... or `search` in `value`.
          value.includes(search)
        ));
      });

    // retrieve the longest (stringified) value's length.
    const bestCoverage = String(
      matchingValues
        .sort((a, b) => b.length - a.length)[0] ?? ''
      ).length;

    if (bestCoverage > coverage) {

      collector.coverage = bestCoverage;
      collector.result = item;
    }
  }
  return collector;
}

const serverSideData = [{
  'prefix': '1',
  'price': 30.5,
}, {
  'prefix': '123',
  'price': 10.5,
}, {
  'prefix': '12345',
  'price': 22.5,
}];

const apiRequest = {
  value: '123456789',
  // or even
  // value: 123456789,
};
const apiResponse = serverSideData
  .reduce(collectItemOfBestCoveringEntryValue, {

    search: String(apiRequest.value),
    result: null,

  }).result;

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.