Home > Blockchain >  Dynamically groupby on an array of objects by number of equal characters
Dynamically groupby on an array of objects by number of equal characters

Time:04-19

What is the best way to groupby objects in an array ?

For example, given this array of objects:

[ 
    { MachineName: "10020784 machineTypeA P.", Value: "5" },
    { MachineName: "80346 machineTypeA s", Value: "10" },
    { MachineName: "80349 machineTypeA k", Value: "15" },
    { MachineName: "80427 machineTypeA w", Value: "20" },
    { MachineName: "machineTypeX", Value: "25" },
    { MachineName: "machineTypeX", Value: "30" },
    { MachineName: "machineTypeX", Value: "35" },
    { MachineName: "machineTypeOther", Value: "40" }
    { MachineName: "machineTypeOther", Value: "40" }
    
]

What I’m looking for would be able to total specific values (if requested).

So if I did groupby MachineName, I’d want to receive:

  [
        { MachineName: " machineTypeA .", Value: "50" },
        { MachineName: "machineTypeX", Value: "90" },
        { MachineName: "other", Value: "80" } 
  ]

I currently use the Array.prototype.some() function :

    Ausgabe = []    
    _.forEach(data, element => {  
          
          obj = {
         
            MachineName: element.MachineName,
            Value: element.Value,
          
          }
        Ausgabe.push(obj);
        
        })
        
         items1 = Ausgabe.filter(item => item.Anlage.indexOf('machineTypeA') !== -1);
         items2 = Ausgabe.filter(item => item.Anlage.indexOf('machineTypeX') !== -1);
         items3 = Ausgabe.filter(item => item.Anlage.indexOf('machineType') !== -1);

if (items1.length <= null){

} 
else {
for (var i = 0; i < items1.length; i  ){ // DZ
  if (items1[i].Value <= null){
    //count   ;
     object1 = {
    MachineName : 'machineTypeA', 
  }   
}  else {
     if (items1[i].Value != null){
     object1 = {
    MachineName:'machineTypeA',
    Value: items1[i].Value , 
    
  }  
}
} 
}
 Ausgabe2.push(object1)
}

if (items2.length  <= null){

} else {
for (var i = 0; i < items2.length; i  ){ // DZ
  if (items2[i].Value <= 0){
    //count   ;
     object2 = {
    MachineName : 'machineTypeX', 
  }   
}  else {
     if (items1[i].MRT != null){
     object2 = {
    Value : 'machineTypeX',
    MachineName : items2[i].Value , 
  }  
}
} 
}
 Ausgabe2.push(object2)
}


if(items3.length <= null){

} 
else {
for (var i = 0; i < items3.length; i  ){ // DZ
  if (items3[i].Value <= 0){
    //count   ;
     object3 = {
    MachineName : 'machineTypeOther', 
  }   
}  else {
     if (items3[i].Value != null){
     object3 = {
    MachineName : 'machineTypeOther',
    Value : items3[i].Value , 
    
  }  
}
} 
}
 Ausgabe2.push(object3)
}

The problem I have with this solution is that its fine for a small array , but for a larger arrays its ineffective because I would need to create x number of 'items'.

If the MachineName would be equal I could use the following :

var groupBy = function(xs, key) {
  return xs.reduce(function(rv, x) {
    (rv[x[key]] = rv[x[key]] || []).push(x);
    return rv;
  }, {});
};

Is there a way to look for x amount of equal characters in a row and then group them accordingly ?

CodePudding user response:

I think it's best to break the problem down. First split all of the machine names from your list on empty space character, then get distinct values. Next filter those values based on if the first character is a letter and the length is greater than X.

Finally use those filtered names to group the machine objects and Sum the values Fiddle.

    int minimumLengthOfName = 3;
    var machines = new[] 
    {
        new { MachineName= "10020784 machineTypeA P.", Value= "5" },
        new { MachineName= "80346 machineTypeA s", Value= "10" },
        new { MachineName= "80349 machineTypeA k", Value= "15" },
        new { MachineName= "80427 machineTypeA w", Value= "20" },
        new { MachineName= "machineTypeX", Value= "25" },
        new { MachineName= "machineTypeX", Value= "30" },
        new { MachineName= "machineTypeX", Value= "35" },
        new { MachineName= "machineTypeOther", Value= "40" },
        new { MachineName= "machineTypeOther", Value= "40" }
    };

    var names = machines.Select(x=> x.MachineName);
    var filteredNames = names.SelectMany(x=> x.Split(' ')) // Split MachineName on empty space and get as a list
        .Distinct() // Get distinct values from out list of split strings
        .Where(x=> Char.IsLetter(x[0]) && x.Length >= minimumLengthOfName); // Get where first character is a letter and the length is greater or equal to minimumLengthOfName
    
    // Now we have each unique machine name we can loop through them and total the matching machines values
    foreach(var name in filteredNames){
        var total = machines.Where(x=> x.MachineName.Contains(name))
            .Sum(x=> Int32.Parse(x.Value));
        Console.WriteLine("MachineName: {0}, Value {1}", name, total);
    }

CodePudding user response:

First we get all the unique names and filter out any that don't match your terms. Then using this unique list we filter the main array and sum the values using the reduce method.

let arr = [ 
    { MachineName: "10020784 machineTypeA P.", Value: "5" },
    { MachineName: "80346 machineTypeA s", Value: "10" },
    { MachineName: "80349 machineTypeA k", Value: "15" },
    { MachineName: "80427 machineTypeA w", Value: "20" },
    { MachineName: "machineTypeX", Value: "25" },
    { MachineName: "machineTypeX", Value: "30" },
    { MachineName: "machineTypeX", Value: "35" },
    { MachineName: "machineTypeOther", Value: "40" },
    { MachineName: "machineTypeOther", Value: "40" },
    { MachineName: "machineTypeOther", Value: "40" },
]
let terms = "machineType"
//Get unique list of Names and filter out ones not with your term;
let unique = [... new Set(arr.flatMap(m => m.MachineName.split(' ')).filter(n => n.includes(terms)))];
// Create a new array from those values and sum totals;
let resultObj = unique.map(m=> ({ 
  MachineName: m, 
  Value: arr
    .filter(i => i.MachineName.includes(m))
    .reduce((v,o) => v = o.Value,0) 
}))

console.log(resultObj);

CodePudding user response:

Do you mean order by? Otherwise use groupBy

const collection = [{
    MachineName: "10020784 machineTypeA P.",
    Value: "5"
  },
  {
    MachineName: "80346 machineTypeA s",
    Value: "10"
  },
  {
    MachineName: "80349 machineTypeA k",
    Value: "15"
  },
  {
    MachineName: "80427 machineTypeA w",
    Value: "20"
  },
  {
    MachineName: "machineTypeX",
    Value: "25"
  },
  {
    MachineName: "machineTypeX",
    Value: "30"
  },
  {
    MachineName: "machineTypeX",
    Value: "35"
  },
  {
    MachineName: "machineTypeOther",
    Value: "40"
  }, {
    MachineName: "machineTypeOther",
    Value: "40"
  }
];

const ordered = _.orderBy(collection, 'MachineName');
console.log(ordered);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>

  • Related