1

I'm trying to write an algorithm that sorts this table by an average value from the each column grouped by the first column(name) so the table display only a rows with the most common values.For example this is the current table:

unsorted table

and after sorting should look like this:

sorted table

So this is the array I'm trying to sort and show only the most common table values:

            var testArray = [
            {
                "testName": "10b1",
                "SG": 1.010,
                "pH":6,
                "LEU": "NEG",
                "NIT": "NEG",
                "PRO": "NEG",
                "GLU": "NORM",
                "KET": "NEG",
                "UBG": "NORM",
                "BIL": "NEG",
                "Hb": "NEG"

            },
            {
                "testName": "10b1",
                "SG": 1.010,
                "pH":6,
                "LEU": "NEG",
                "NIT": "NEG",
                "PRO": "NEG",
                "GLU": "NORM",
                "KET": "NEG",
                "UBG": "NORM",
                "BIL": "NEG",
                "Hb": "NEG"
            },
            {
                "testName": "10b1",
                "SG": 1.010,
                "pH":6,
                "LEU": "NEG",
                "NIT": "NEG",
                "PRO": "NEG",
                "GLU": "NORM",
                "KET": "NEG",
                "UBG": "NORM",
                "BIL": "NEG",
                "Hb": "NEG"
            },
            {
                "testName": "10b1",
                "SG": 1.010,
                "pH":6,
                "LEU": "NEG",
                "NIT": "NEG",
                "PRO": "NEG",
                "GLU": "NORM",
                "KET": "NEG",
                "UBG": "NORM",
                "BIL": "NEG",
                "Hb": "NEG"
            },
            {
                "testName": "10b1",
                "SG": 1.010,
                "pH":6,
                "LEU": "NEG",
                "NIT": "NEG",
                "PRO": "NEG",
                "GLU": "NORM",
                "KET": "NEG",
                "UBG": "NORM",
                "BIL": "NEG",
                "Hb": "NEG"
            },
            {
                "testName": "10b1.5",
                "SG": 1.010,
                "pH":6,
                "LEU": "NEG",
                "NIT": "NEG",
                "PRO": "NEG",
                "GLU": 50,
                "KET": "NEG",
                "UBG": "NORM",
                "BIL": "NEG",
                "Hb": 50
            },
            {

                "testName": "10b1.5",
                "SG": 1.010,
                "pH":6,
                "LEU": "NEG",
                "NIT": "NEG",
                "PRO": "NEG",
                "GLU": 50,
                "KET": "NEG",
                "UBG": "NORM",
                "BIL": "NEG",
                "Hb": 50
            },
            {
                "testName": "10b1.5",
                "SG": 1.010,
                "pH":6,
                "LEU": "NEG",
                "NIT": "NEG",
                "PRO": "NEG",
                "GLU": 50,
                "KET": "NEG",
                "UBG": "NORM",
                "BIL": "NEG",
                "Hb": 50
            }
        ];

I tried to use this algorithm but the result that returns me is far from the expected result:

  var mf = 1;
        var m = 0;
        var item;
        var count = 1;
        for(let k = 0; k < testArray.length; k++){
            for(let v = 0; v < testArray[k].values.length; v++){
                 current = 1;
                for(j = v; j <= testArray[k].values.length; j++){
                    if(testArray[k].values[v] == testArray[k].values[j]){
                        m++;
                    }

                    if(mf < m){
                        mf=m;
                        item = testArray[k].values[v];
                        testArray[k].values = [];
                    }
                }
                    testArray[k].values[v] = item;

            }

        }

I would be grateful if someone can give some sample algorithm or solution to the problem :)

jorobash
  • 23
  • 5
  • 1
    Why does the output have 2 rows if you want to get *"only the most common table values*" from each column? – adiga May 05 '19 at 17:42
  • 4
    Also, please don't upload [images of your code](https://meta.stackoverflow.com/a/285557/3082296). The image of your array cannot be copied to create an answer and images harder to read than text. Please post the actual code **as text** to create a [mcve]. – adiga May 05 '19 at 17:47
  • I would like to display the most common values in the table grouped by name so for each name should display most common value, and the table currently has two names: "10b1", "10b1.5". So for each name I have to get the most common values. – jorobash May 06 '19 at 17:20
  • You are right about the photo of the array @adiga I'm really sorry about the image.. so I edited my question and set the current array, which is a valid JSON and can be used to write an example solution now. – jorobash May 06 '19 at 17:37

1 Answers1

0

You can loop through the array and create a nested object to group the array based on on name and then by key and finally by the value for each key. Then loop through the entries of this counts nested obj and create an object based on the mode of values for each key

This is what the counts object looks like:

{
    "10b1": {
        "SG": {
            "1.01": 5
        },
        "pH": {
            "6": 5
        },
        "LEU": {
            "NEG": 5
        },
        "NIT": {
            "NEG": 5
        },
        "PRO": {
            "NEG": 5
        },
        "GLU": {
            "NORM": 5
        },
        "KET": {
            "NEG": 5
        },
        "UBG": {
            "NORM": 5
        },
        "BIL": {
            "NEG": 5
        },
        "Hb": {
            "10": 3,
            "NEG": 2
        }
    },
    "10b1.5": {
        "SG": {
            "1.01": 3
        },
        "pH": {
            "6": 3
        },
        "LEU": {
            "NEG": 3
        },
        "NIT": {
            "NEG": 3
        },
        "PRO": {
            "NEG": 3
        },
        "GLU": {
            "50": 3
        },
        "KET": {
            "NEG": 3
        },
        "UBG": {
            "NORM": 3
        },
        "BIL": {
            "NEG": 3
        },
        "Hb": {
            "50": 3
        }
    }
}

Here's a working snippet:

{ testName, ...rest } in the reduce parameter is for destructuring each object to a separate testName and remaining properties to a rest object

var array=[{testName:"10b1",SG:1.01,pH:6,LEU:"NEG",NIT:"NEG",PRO:"NEG",GLU:"NORM",KET:"NEG",UBG:"NORM",BIL:"NEG",Hb:"NEG"},{testName:"10b1",SG:1.01,pH:6,LEU:"NEG",NIT:"NEG",PRO:"NEG",GLU:"NORM",KET:"NEG",UBG:"NORM",BIL:"NEG",Hb:"10"},{testName:"10b1",SG:1.01,pH:6,LEU:"NEG",NIT:"NEG",PRO:"NEG",GLU:"NORM",KET:"NEG",UBG:"NORM",BIL:"NEG",Hb:"NEG"},{testName:"10b1",SG:1.01,pH:6,LEU:"NEG",NIT:"NEG",PRO:"NEG",GLU:"NORM",KET:"NEG",UBG:"NORM",BIL:"NEG",Hb:"10"},{testName:"10b1",SG:1.01,pH:6,LEU:"NEG",NIT:"NEG",PRO:"NEG",GLU:"NORM",KET:"NEG",UBG:"NORM",BIL:"NEG",Hb:"10"},{testName:"10b1.5",SG:1.01,pH:6,LEU:"NEG",NIT:"NEG",PRO:"NEG",GLU:50,KET:"NEG",UBG:"NORM",BIL:"NEG",Hb:50},{testName:"10b1.5",SG:1.01,pH:6,LEU:"NEG",NIT:"NEG",PRO:"NEG",GLU:50,KET:"NEG",UBG:"NORM",BIL:"NEG",Hb:50},{testName:"10b1.5",SG:1.01,pH:6,LEU:"NEG",NIT:"NEG",PRO:"NEG",GLU:50,KET:"NEG",UBG:"NORM",BIL:"NEG",Hb:50}];

const counts = array.reduce((acc, { testName, ...rest }) => {
   if(!acc[testName]) acc[testName] = {};

   let nested = acc[testName];
   
   Object.entries(rest).forEach(([key, value]) => {
    if(!nested[key]) nested[key] = {}
    
    nested[key][value] = nested[key][value] + 1 || 1;
  })
  
  return acc
},{})

const output = Object.entries(counts).map(([testName, count]) => {
  const obj = { testName };
  
  Object.entries(count).forEach(([k, v]) => {
    const mode = Object.keys(v).sort((a, b) => v[b] - v[a])[0];
    obj[k] = mode;
  }, {})
  
  return obj
})

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

(None of the keys had more than one unique value. So, for the 10b1 name's Hb property, I have used: "NEG", "10", "NEG", "10", "10" values -- same as the image for demonstration)

adiga
  • 34,372
  • 9
  • 61
  • 83
  • Thanks @adiga :), It's work like a charm. Is there any way to return the array ordered, because it is out of order.now? – jorobash May 07 '19 at 19:59
  • @jorobash what do you mean by order? It's currently shows `10b1` first and then `10b1.5`? Because that's the order in the original array – adiga May 08 '19 at 02:52
  • Yes the order of the names is correct, what I mean is when I test the code in the browser It's work, but the order of the "SG", "pH", "LEU", "NIT", "PRO" ...... etc is shuffle.Returns them this way: `0: {…} ​​ BIL: "NEG" ​​ GLU: "NORM" ​​ Hb: "10" ​​ KET: "NEG" ​​ LEU: "NEG" ​​ NIT: "NEG" ​​ PRO: "NEG" ​​ SG: "1.01" ​​ UBG: "NORM" ​​ pH: "6" ​​ testName: "10b1" ​ ​ 1: {…} ​​ BIL: "NEG" ​​ GLU: "50" ​​ Hb: "50" ​​ KET: "NEG" ​​ LEU: "NEG" ​​ NIT: "NEG" ​​ PRO: "NEG" ​​ SG: "1.01" ​​ UBG: "NORM" ​​ pH: "6" ​​ testName: " 10b1.5" ​​` – jorobash May 08 '19 at 20:05
  • @jorobash Not sure what you're asking here. In the example I have provided, in the input array, the objects have keys in the order of `"SG", "pH", "LEU", "NIT", "PRO", "GLU", "KET", "UBG", "BIL", "Hb"`. Same order is being maintained in the output's objects order. This is true at least for ES6 anyway: [Does JavaScript Guarantee Object Property Order?](https://stackoverflow.com/questions/5525795) – adiga May 08 '19 at 20:12
  • Thanks @adiga you really help me! – jorobash May 09 '19 at 19:16
  • @jorobash you can [accept the answer](https://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work) by clicking on the grey checkmark on the left of the answer – adiga May 09 '19 at 19:17