0

The following function matches the strings in a file (queries) with the strings of another two files (archives). I included the important logs:

console.log('q:', queries)
console.log('a:', archives)
queries.forEach(query => {
  const regex = new RegExp(query.trim(), 'g')
  archives.forEach(archive => {
    const matched = archive.match(regex)
    console.log('m:', matched)
  })
})

q: [ 'one two', 'three four\n' ]
a: [ 'one two three four three four\n', 'one two three four\n' ]
m: [ 'one two' ]
m: [ 'one two' ]
m: [ 'three four', 'three four' ]
m: [ 'three four' ]

How to modify the code so I merge matched and end up with a result like this?

r1: [ 'one two',  'one two' ]
r2: [ 'three four', 'three four', 'three four' ]

(Maybe I can use .reduce but I'm not very sure how.)

EDIT: I tried this:

  const result = matched.reduce(function (a, b) {
    return a.concat(b)
  }, [])

But ended up with the same result.

alex
  • 7,111
  • 15
  • 50
  • 77

3 Answers3

1

This should do it:

var queries = [ 'one two', 'three four\n' ],
    archives = [ 'one two three four three four\n', 'one two three four\n' ],
    results = {};

queries.forEach(query => {
  const regex = new RegExp(query.trim(), 'g')
  archives.forEach(archive => {
    const matched = archive.match(regex)
    results[matched[0]] = (results[matched[0]] || []).concat(matched) || matched;
  })
})

console.log(results)

Store the results in an object, using the found string as a key.

For some cleaner data, you can just get the match counts, as fafl suggested:

var queries = [ 'one two', 'three four\n' ],
    archives = [ 'one two three four three four\n', 'one two three four\n' ],
    results = {};

queries.forEach(query => {
  const regex = new RegExp(query.trim(), 'g')
  archives.forEach(archive => {
    const matched = archive.match(regex)
    results[matched[0]] = (results[matched[0]] || 0) + matched.length
  })
})

console.log(results)
Cerbrus
  • 70,800
  • 18
  • 132
  • 147
  • Strange, the result seems a bit different for me: `{ 'one two': [ 'one two', 'one two' ] } { 'three four': [ 'three four', 'three four', 'three four' ] }` – alex Nov 29 '16 at 15:13
  • @alex: Yes, it generates a single object. This is [easier to work with](http://stackoverflow.com/questions/684672/how-do-i-loop-through-or-enumerate-a-javascript-object) than separate variables. – Cerbrus Nov 29 '16 at 15:21
  • When you're already changing the result, just store the count instead: `{"one two": 2, "three four": 3}` – fafl Nov 29 '16 at 15:23
1
let queries = [ 'one two', 'three four\n' ],
    archives = [ 'one two three four three four\n', 'one two three four\n' ]

queries.forEach(query => {
  let regex = new RegExp(query.trim(), 'g')

  // first, you need to collect the matched result into a new array
  // forEach will do the process you specified, but won't return any value
  // "map" is the better choice, as it will return the process result
  let result = archives.map(archive => {

    return archive.match(regex)

    // now you could reduce against the new array
  }).reduce(function(a, b) {
    return a.concat(b); 
  }, [])

  console.log(result)

})

One more thing, I don't see "const" will do anything good here, it just let think about why it has to be something unchangeable. So "let" is better to use for reduce the confusion.

Hetfield Joe
  • 1,443
  • 5
  • 15
  • 26
1

You don't need reduce for this:

var flatten = arr => [].concat.apply([], arr)
queries.map(q =>
  flatten(
    archives.map(a =>
      a.match((new RegExp(q.trim(), 'g')))
    )
  )
)
fafl
  • 7,222
  • 3
  • 27
  • 50
  • `[].concat.apply([], arr)` is used to flatten a 2D array. I don't think there is a better way that involves `spread`. I changed my answer to be a bit more readable. – fafl Nov 29 '16 at 16:29