【问题标题】:How to get n number of value from array according to the weightage value in javascript如何根据javascript中的权重值从数组中获取n个值
【发布时间】:2020-07-19 06:35:10
【问题描述】:

我有一个这样的数组,其中包含大约 30 万个条目。

var data = [
 {name: "peter", city: "bauru", weightage: 20},
 {name: "marcos", city: "belo", weightage: 15},
 {name: "rio", city: "salvador", weightage: 20},
 {name: "halter", city: "natal", weightage: 15},
 {name: "ron", city: "belem", weightage: 15},
 {name: "dominic", city: "santos", weightage: 15},
 {name: "john", city: "bauru", weightage: 20},
 {name: "ros", city: "natal", weightage: 15},
 {name: "nick", city: "salvador", weightage: 20},
 {name: "david", city: "santos", weightage: 15},
 {name: "ison", city: "belem", weightage: 15},
 {name: "eddy", city: "belo", weightage: 15},
....
 
]

我在一个数组中有条目,每个不同的用户都位于这 6 个城市下。每个城市都有权重值。所以我要根据权重值随机挑选60000条数据。

我尝试首先分离数据并从 bauru 中选择 20% 的数据,从 belo 中选择 15% 的数据等等,但这种手动操作并不是一个好方法。

我不知道在 javascript 上写这个。

预期输出:我想要 60k 数据,其中 20% 的值来自 bauru,15% 来自贝洛,20% 来自萨尔瓦多,15% 来自 natal,15%来自贝伦,15% 来自桑托斯。总数为 60k。如果任何城市数据总计没有出现 15% 或 20%,则从 20% 和 15% 中选择更多数据。假设 60k 数据的 15% = 7200,任何城市的总值只有 500,那么我们从数据量大的不同城市的 20% 或 15% 中挑选其余数据

【问题讨论】:

  • 你有没有尝试过?
  • 可以添加一些随机数据吗?
  • @NinaScholz 我添加了更多数据。在这个唯一的用户名和城市都被改变了。你可以说它是一个来自少数几个城市的用户列表,其中有 30 万个条目。其中我想要 60k 数据。现在 60k 数据是权重值的组合

标签: javascript arrays ecmascript-6


【解决方案1】:

您可以先按城市分组,然后从组中选择项目的数量。

var data = [{ name: "peter", city: "bauru", weightage: 20 }, { name: "marcos", city: "belo", weightage: 15 }, { name: "rio", city: "salvador", weightage: 20 }, { name: "halter", city: "natal", weightage: 15 }, { name: "ron", city: "belem", weightage: 15 }, { name: "dominic", city: "santos", weightage: 15 }, { name: "john", city: "bauru", weightage: 20 }, { name: "ros", city: "natal", weightage: 15 }, { name: "nick", city: "salvador", weightage: 20 }, { name: "david", city: "santos", weightage: 15 }, { name: "ison", city: "belem", weightage: 15 }, { name: "eddy", city: "belo", weightage: 15 }, { name: "queen", city: "bauru", weightage: 20 }, { name: "lucia", city: "belo", weightage: 15 }, { name: "fran", city: "salvador", weightage: 20 }, { name: "yvonne", city: "natal", weightage: 15 }, { name: "audry", city: "belem", weightage: 15 }, { name: "gaby", city: "santos", weightage: 15 }, { name: "susan", city: "bauru", weightage: 20 }, { name: "tonya", city: "natal", weightage: 15 }, { name: "ines", city: "salvador", weightage: 20 }, { name: "karen", city: "santos", weightage: 15 }, { name: "petra", city: "belem", weightage: 15 }, { name: "jane", city: "belo", weightage: 15 }, { name: "jo", city: "bauru", weightage: 20 }, { name: "kim", city: "belo", weightage: 15 }, { name: "tony", city: "salvador", weightage: 20 }, { name: "adrian", city: "natal", weightage: 15 }, { name: "alex", city: "belem", weightage: 15 }, { name: "dana", city: "santos", weightage: 15 }, { name: "sam", city: "bauru", weightage: 20 }, { name: "nicola", city: "natal", weightage: 15 }, { name: "finn", city: "salvador", weightage: 20 }, { name: "sasha", city: "santos", weightage: 15 }, { name: "kay", city: "belem", weightage: 15 }, { name: "ira", city: "belo", weightage: 15 }],
    target = 20,
    groups = data.reduce((r, o) => {
        if (!r[o.city]) r[o.city] = [];
        r[o.city].push(o);
        return r;
    }, {}),
    result = Object.keys(groups).reduce((r, k) => {
        let count = Math.floor(target * groups[k][0].weightage/ 100);
        while (count-- && groups[k].length)
            r.push(groups[k].splice(Math.floor(Math.random() * groups[k].length), 1)[0]);
        return r;
    }, []);

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

【讨论】:

    【解决方案2】:

    此解决方案按城市对所有数据进行分组,随机化每组中记录的顺序,并从每组中获取前 X 条记录,其中 X 是达到所需权重所需的总数。

    在样本数据中,总数为 3、4 和 3,而在您的实际数据中,大多数城市(权重 15)使用 9000,其他城市使用 12(权重 20)。

    (上次我查看您的问题时,您尚未添加规范,即某些城市可能没有足够的数据来达到其所需的权重,因此未处理这种情况,但我也许可以添加一些内容如果您仍然需要帮助,请明天再做。)

        // Creates the `cities` object and retrieves data
        const
          cities = getCities(),
          data = getData();
    
        // Copies all records from `data` into cities, grouped by city
        data.reduce( (acc, item) =>
          addRecordToCity(item, item.city), cities);
    
        // Randomizes and then truncates each city-specific array
        Object.keys(cities).forEach(city => {
          let
            cityData = cities[city].data,
            numberNeeded = cities[city].total;
          cities[city].data = shuffle(cityData).slice(0, numberNeeded);
        });
    
        // Prints results
        console.log("Selections:")
        Object.keys(cities).forEach(city => {
          cities[city].data.forEach(item =>
            console.log(item.name, item.city)
          );
        });
    
    
        // Coptes a record from `data` into `cities`, in the appropriate city
        function addRecordToCity(record, cityName){
          cities[cityName].data.push(record);
          return cities;
        }
    
        // Randomizes an array
        function shuffle(array){
          let i = array.length, rand, temp;
          while(--i > 0){
            rand = Math.floor( Math.random() * (i + 1) );
            temp = array[rand];
            array[rand] = array[i]
            array[i] = temp;
          }
          return array;
        }
    
        // Defines the cities object that will hold our final results
        function getCities(){
          return {  // Weightages are 30/40/30, collecting 10 records total
            "city_1": { total: 3, data: [] },
            "city_2": { total: 4, data: [] },
            "city_3": { total: 3, data: [] }
          };
        }
    
        // Defines source data
        function getData(){
          return [
            { name: "a", city: "city_1" },
            { name: "b", city: "city_2" },
            { name: "c", city: "city_3" },
            { name: "d", city: "city_1" },
            { name: "e", city: "city_2" },
            { name: "f", city: "city_3" },
            { name: "g", city: "city_1" },
            { name: "h", city: "city_2" },
            { name: "i", city: "city_3" },
            { name: "j", city: "city_1" },
            { name: "k", city: "city_2" },
            { name: "l", city: "city_3" },
            { name: "m", city: "city_1" },
            { name: "n", city: "city_2" },
            { name: "o", city: "city_3" },
            { name: "p", city: "city_1" },
            { name: "q", city: "city_2" },
            { name: "r", city: "city_3" }
          ];
        }

    【讨论】:

      【解决方案3】:

      如果您创建一个控制表来指示您希望如何选择样本,这应该相当简单。

      我建议分两步进行。首先将您的完整记录集过滤为仅那些您认为“有效”的记录(即具有正确的城市/年龄组合),然后您可以在最终集中挑选您想要的人:

      var data = [
       {name: "peter", city: "bauru", weightage: 20},
       {name: "marcos", city: "belo", weightage: 15},
       {name: "rio", city: "salvador", weightage: 20},
       {name: "halter", city: "natal", weightage: 15},
       {name: "ron", city: "belem", weightage: 15},
       {name: "dominic", city: "santos", weightage: 15},
       {name: "john", city: "bauru", weightage: 20},
       {name: "ros", city: "natal", weightage: 15},
       {name: "nick", city: "salvador", weightage: 20},
       {name: "david", city: "santos", weightage: 15},
       {name: "ison", city: "belem", weightage: 15},
       {name: "eddy", city: "belo", weightage: 15}
      ]
      
      //create a control array with the matches you want (city/weightage etc) 
      //include the result percent you care about
      let controlArray = [
        {city: "bauru", weightage: 20, resultPercent : .2},
        {city: "belo", weightage: 15, resultPercent : .2},
        {city: "salvador", weightage: 20, resultPercent : 0},
        {city: "natal", weightage: 15, resultPercent : .2},
        {city: "belem", weightage: 15, resultPercent : .2},
        {city: "santos", weightage: 15, resultPercent : .2}
      ];
      
      //this is your result set
      let validRecords = [];
      
      //this is your sample size - I've used 5 as the sample data was only 12 rows
      let requiredRecords = 5;
      
      //iterate over the control array
      controlArray.forEach(controlRecord => {
          //available records - here you filter out records that don't match your criteria
          let availablePeople = data.filter(individual => {return individual.city == controlRecord.city && individual.weightage == controlRecord.weightage});
        
          //get a sample from the reduced set
          let requiredNumberFromSet = Math.ceil(controlRecord.resultPercent*requiredRecords);
      
          validRecords = validRecords.concat(availablePeople.slice(0, requiredNumberFromSet));
      });
      
      //your result set, here you should see five records - one from each city excluding salvador which I set to 0% for this demo.
      console.log(validRecords);
      

      如果一组没有足够的有效匹配项,您也可以相当容易地在此方法中添加“溢出”逻辑,您可以将其存储为变量并将其添加到下一个控制行中的选择中。

      【讨论】:

        猜你喜欢
        • 2015-09-13
        • 2023-02-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-30
        • 2021-09-13
        • 2015-07-02
        • 2021-09-22
        • 2018-11-15
        相关资源
        最近更新 更多