how to calculate the count of same values for all nested object?

Viewed 68

Hi Could I ask some difficult algorithm question?

109.169.248.247
109.169.248.247
109.169.248.248
109.170.248.248
46.72.177.3
46.72.177.4

From the input above, I would like to print the following, I am using diverse approaches, but I am not good at algorithm, so it is very hard to achieve this, does anyone have solution for this?

109 4
    169 3
        248 3
            247 2
            248 1
    170 1
        248 1
            248 1
46 2
    72 2
        177 2
            3 1
            4 1

By using this code, I can calculate the number of the whole ip's count, but I can't calculate the number for each ip segment's count. Could you please help me with solving this problem?

function assign(obj, keyPath, value) {
    lastKeyIndex = keyPath.length-1;
    firstCreated = false;
    for (var i = 0; i < lastKeyIndex; ++ i) {
        key = keyPath[i];
        if (!(key in obj)) {
            obj[key] = {};
            firstCreated = true;
        }
        obj = obj[key];
    }
    if(firstCreated) {
        obj[keyPath[lastKeyIndex]] = parseInt(value);
    }
    else {
        obj[keyPath[lastKeyIndex]] = parseInt(obj[keyPath[lastKeyIndex]]) + 1;
    }
 }
3 Answers

Implementing @dpwrussel's comment: create the Trie from the ips, then print the tree.

const ips = `
109.169.248.247
109.169.248.247
109.169.248.248
109.170.248.248
46.72.177.3
46.72.177.4
`

const IPTrie = function (ips) {
  this.root = new Map()
  for (const ip of ips.trim().split('\n')) {
    this.add(ip)
  }
  return this
}

IPTrie.prototype.add = function (ip) {
  const parts = ip.split('.')
  let cursor = this.root,
    index = -1
  while (++index < parts.length) {
    const part = parts[index]
    if (cursor.has(part)) {
      const [count, node] = cursor.get(part)
      cursor.set(part, [count + 1, node])
      cursor = node
    } else {
      let node = new Map()
      cursor.set(part, [1, node])
      cursor = node
    }
  }
}

IPTrie.prototype.print = function (cursor, indent = 0) {
  cursor = cursor || this.root
  for (const [part, entry] of cursor) {
    const [count, node] = entry
    console.log(`${' '.repeat(indent)}${part} ${count}`)
    this.print(node, indent + 4)
  }
}

new IPTrie(ips).print()

my way.. (for a start,could be recursive)

const IHM = document.querySelector('pre')
  , IPn = 
    [ '109.169.248.247'
    , '109.169.248.247'
    , '109.169.248.248'
    , '109.170.248.248'
    , '46.72.177.3'
    , '46.72.177.4'
    ]
    
    
let bob = IPn.reduce((r,k)=>
  {
  let [o1,o2,o3,o4] = k.split('.')
    , k1  = r.find(x=>x.k===o1)
    ;
  if(!k1) { k1 = { k:o1, n:0, c:[] };  r.push(k1) }
  ++k1.n
   
  let k2 = k1.c.find(x=>x.k===o2)
  if(!k2) { k2 = { k:o2, n:0, c:[] }; k1.c.push(k2) }
  ++k2.n

  let k3 = k2.c.find(x=>x.k===o3)
  if(!k3) { k3 = { k:o3, n:0, c:[] }; k2.c.push(k3)}
  ++k3.n

  let k4 = k3.c.find(x=>x.k===o4)
  if(!k4) { k4 = { k:o4, n:0 }; k3.c.push(k4)}
  ++k4.n

  return r
  },[])

bob.forEach(ip0=>
  {
  IHM.textContent +=  ip0.k.padStart(6,' ') + '__' +ip0.n + '\n'
  ip0.c.forEach(ip1=>
    {
    IHM.textContent +=  ip1.k.padStart(12,' ') + '__' +ip1.n + '\n'
    ip1.c.forEach(ip2=>
      {
      IHM.textContent +=  ip2.k.padStart(18,' ') + '__' +ip2.n + '\n'
      ip2.c.forEach(ip3=>
        {
        IHM.textContent +=  ip3.k.padStart(24,' ') + '__' +ip3.n + '\n'
        })   
      })    
    })
  })
<pre></pre>

second Solution can work for IP v6 address (Recursive)

const IHM = document.querySelector('pre')
  , IPn = 
      [ '109.169.248.247'  , '109.169.248.247', '109.169.248.248'  
      , '109.170.248.248'  , '46.72.177.3'    , '46.72.177.4'
      ]
  , SetTree = (Keys,Tree) =>
      {
      let octet = Keys.shift()
        , ref   = Tree.find(x=>x.k===octet)
        ;
      if (!ref) { ref = {k:octet, n:1, c:[] }; Tree.push( ref )}
      ++ref.n
      if (!!Keys[0]) SetTree(Keys, ref.c )
      }
  , DisplayTree = ( Tree, disp, vPad) =>
      {
      Tree.forEach(IPv=>
        {
        disp.textContent += IPv.k.padStart(vPad, ' ') + '-' +IPv.n + '\n'
        if(!!IPv.c[0]) DisplayTree( IPv.c, disp, vPad +6)
        })
      }
  , TreeRef = []  // IP Tree, can work for IP v6 address
  ;
IPn.forEach(IP => SetTree( IP.split('.'), TreeRef) ) // the job...
 
DisplayTree( TreeRef, IHM, 5)  // show result
<pre></pre>

Related