0

I am facing one problem in javascript filter.

Suppose this is an array1-

const array1 = [
    {
        title: 'Stock market news',
        symbols: ['SPY.US', 'GSPC.INDX', 'DJI.INDX', 'CL.COMM', 'IXIC.INDX', 'NQ.COMM', 'ES.COMM'],
    },
    {
        title: 'Neil Young urges Spotify',
        symbols: ['SPOT.US', '639.F', '639.XETRA']
    },
    {
        title: 'Neil Young urges Spotify',
        symbols: ['AAPl.US', '639.F', '639.XETRA']
    }
]

And this is an array2

const array2 = [
    {Code: "AAPL"},
    {Code: 'SPOT'}
]

I have to filer array1 and remove an object that not complete the condition. The condition is if the array1 symbols contain at least one element of array2 Code. I mean if the array2 Code is match arry1 symbols field at least one element.

In the above example, the result should be-

const array1 = [
    {
        title: 'Neil Young urges Spotify',
        symbols: ['SPOT.US', '639.F', '639.XETRA']
    },
    {
        title: 'Neil Young urges Spotify',
        symbols: ['AAPl.US', '639.F', '639.XETRA']
    }
]

Because this two object contain AAPL and SPOT in symbols field. I think I can clear all the things.

I am trying in this way-

const filterData = array1.filter(function (array1El) {
    return !array2.find(function (array2El) {
        return array1El.symbols.includes(`${array2El.Code}.US`);
    })
});

But it is not working. Please say me where I am wrong.

1

3 Answers 3

1

There are two issues:

  • Your !array2.find condition is backwards - you want to filter to include items for which array2.find does have a match, not items for which it doesn't.
  • 'AAPl.US' !== 'AAPL.US' - make them the same case before comparing.

It'd also be clearer to use .some instead of .find.

const array1 = [
    {
        title: 'Stock market news',
        symbols: ['SPY.US', 'GSPC.INDX', 'DJI.INDX', 'CL.COMM', 'IXIC.INDX', 'NQ.COMM', 'ES.COMM'],
    },
    {
        title: 'Neil Young urges Spotify',
        symbols: ['SPOT.US', '639.F', '639.XETRA']
    },
    {
        title: 'Neil Young urges Spotify',
        symbols: ['AAPl.US', '639.F', '639.XETRA']
    }
]

const array2 = [
    {Code: "AAPL"},
    {Code: 'SPOT'}
]
const filterData = array1.filter(function (array1El) {
    return array2.some(function (array2El) {
        return array1El.symbols
            .map(s => s.toLowerCase())
            .includes(`${array2El.Code.toLowerCase()}.us`);
    })
});
console.log(filterData);

Or create a Set of matching symbols first, which I'd prefer for lower complexity.

const array1 = [
    {
        title: 'Stock market news',
        symbols: ['SPY.US', 'GSPC.INDX', 'DJI.INDX', 'CL.COMM', 'IXIC.INDX', 'NQ.COMM', 'ES.COMM'],
    },
    {
        title: 'Neil Young urges Spotify',
        symbols: ['SPOT.US', '639.F', '639.XETRA']
    },
    {
        title: 'Neil Young urges Spotify',
        symbols: ['AAPl.US', '639.F', '639.XETRA']
    }
]

const array2 = [
    {Code: "AAPL"},
    {Code: 'SPOT'}
];

const codesToFind = new Set(array2.map(({ Code }) => Code.toLowerCase() + '.us'));
const filterData = array1.filter(
  ({ symbols }) => symbols.some(
    sym => codesToFind.has(sym.toLowerCase())
  )
);
console.log(filterData);

Sign up to request clarification or add additional context in comments.

2 Comments

Won't hard-coding the .us suffix eliminate ever being able to query for the .F and .EXTRA symbols?
That appears to be the same logic OP is trying to use with .includes(`${array2El.Code}.US`);. Perhaps he's intentionally trying to only find .US.
0

We could use a regex alternation approach here:

const array1 = [
    {
        title: 'Stock market news',
        symbols: ['SPY.US', 'GSPC.INDX', 'DJI.INDX', 'CL.COMM', 'IXIC.INDX', 'NQ.COMM', 'ES.COMM'],
    },
    {
        title: 'Neil Young urges Spotify',
        symbols: ['SPOT.US', '639.F', '639.XETRA']
    },
    {
        title: 'Neil Young urges Spotify',
        symbols: ['AAPL.US', '639.F', '639.XETRA']
    }
];

const array2 = [{Code: "AAPL"}, {Code: "SPOT"}];
var regex = new RegExp("\\b(?:" + array2.reduce((x, y) => x.Code + "|" + y.Code) + ")\\.US");
console.log(regex);  // /\b(?:AAPL|SPOT)\.US/
var output = array1.filter(x => x.symbols.some(e => regex.test(e)));
console.log(output);

The strategy here is to form a regex alternation of stock symbols, one of which is required. We then filter the original array, using some() and the regex to ensure that any match has at least one required stock symbol.

Comments

0

If you're doing this search multiple times, it would be best to build a symbol index and query that.

For example...

const array1 = [{"title":"Stock market news","symbols":["SPY.US","GSPC.INDX","DJI.INDX","CL.COMM","IXIC.INDX","NQ.COMM","ES.COMM"]},{"title":"Neil Young urges Spotify","symbols":["SPOT.US","639.F","639.XETRA"]},{"title":"Neil Young urges Spotify","symbols":["AAPl.US","639.F","639.XETRA"]}]

const array2 = [{Code: "AAPL"},{Code: 'SPOT'}]

// utility function to write into the index
const writeIndex = (map, key, entry) => {
  const normalisedKey = String.prototype.toUpperCase.call(key)
  if (!map.has(normalisedKey)) map.set(normalisedKey, new Set())
  map.get(normalisedKey).add(entry)
}

const symbolIndex = array1.reduce((map, entry) => {
  // convert all symbols to tokens
  // eg AAPL.US becomes ["AAPL.US", "AAPL", "US"]
  const keys = entry.symbols.flatMap(symbol => 
    [symbol, ...symbol.split(".")])
  
  // add the entry for each symbol token
  keys.forEach(key => writeIndex(map, key, entry))
  return map
}, new Map())

// pull unique items out of the index for the given codes
const queryIndex = codes => Array.from(new Set(codes.flatMap(code => 
  [...symbolIndex.get(code) ?? []]
)))

console.log(queryIndex(array2.map(({ Code }) => Code)))
.as-console-wrapper { max-height: 100% !important; }


Alternatively, you can use a nested some clause with a string includes check to see if the symbol contains your code.

const array1 = [{"title":"Stock market news","symbols":["SPY.US","GSPC.INDX","DJI.INDX","CL.COMM","IXIC.INDX","NQ.COMM","ES.COMM"]},{"title":"Neil Young urges Spotify","symbols":["SPOT.US","639.F","639.XETRA"]},{"title":"Neil Young urges Spotify","symbols":["AAPl.US","639.F","639.XETRA"]}]

const array2 = [
    {Code: "AAPL"},
    {Code: 'SPOT'}
]

const normalise = str => str.toUpperCase()

const normalisedCodes = array2.map(({ Code }) => normalise(Code))

const filtered = array1.filter(({ symbols }) =>
  normalisedCodes.some(code =>
    symbols.some(symbol => normalise(symbol).includes(code))
  )
)

console.log(filtered)
.as-console-wrapper { max-height: 100% !important; }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.