【问题标题】:Manipulating JSON into observable array collections将 JSON 操作为可观察的数组集合
【发布时间】:2014-03-23 20:14:55
【问题描述】:

我正在寻求如何处理这个 JSON 的建议:

[{
  "title":"Things",
  "text":"1. Raindrops on roses 2. Whiskers on kittens 3. Bright copper kettles 4. Warm woolen mittens 5. Brown paper packages"
},{
  "title":"Colors",
  "text":"1. White 2. Blue 3. Red 4. Yellow 5. Green"
},{
  "title":"Animals",
  "text":"1. Dog 2. Rabbit 3. Cat 4. Squirrel 5. Duck"
},{
  "title":"Colors",
  "text":"1. Red 2. Blue 3. Orange 4. Green 5. Purple"
},{
  "title":"Animals",
  "text":"1. Bear 2. Bird 3. Duck 4. Squirrel 5. Rabbit"
},{
  "title":"Colors",
  "text":"1. Yellow 2. White 3. Black 4. Brown 5. Blue"
}]

返回这些可观察数组的集合:

  • 标题:颜色,数量:3,项目:
    • 姓名:White,得分:9,计数:2
    • 姓名:Blue,得分:9,计数:3
    • 姓名:Red,得分:8,计数:2
    • 姓名:Yellow,得分:7,计数:2
    • 姓名:布莱克,得分:3,计数:1
    • 姓名:Orange,得分:3,计数:1
    • 姓名:Green,得分:3,计数:2
    • 姓名:布朗,得分:2,计数:1
    • 姓名:Purple,得分:1,计数:1

  • 标题:动物,数量:2,项目:
    • 姓名:熊,得分:5,计数:1
    • 姓名:狗,得分:5,计数:1
    • 姓名:兔子,得分:5,计数:2
    • 姓名:Bird,得分:4,计数:1
    • 名字:鸭子,得分:4,计数:2
    • 姓名:松鼠,得分:4,计数:2
    • 姓名:猫,得分:3,计数:1

  • 标题:事物,计数:1,项目:
    • 名称:玫瑰上的雨滴,得分:5,计数:1
    • 名称:小猫的胡须,得分:4,计数:1
    • 名称:亮铜壶,得分:3,计数:1
    • 名称:保暖羊毛手套,得分:2,计数:1
    • 名称:牛皮纸包装,得分:1,计数:1

为了解释,我需要做以下事情:

  1. title 对所有数组进行分组,计算它们的频率并返回新的列表对象,例如Title: Colors, Count: 3
  2. 按数字分隔符拆分每个text 项目以创建项目数组,计算它们的频率,根据索引位置为它们分配一个分数(即[0] = 5 到[4] = 1),将它们的分数相加并返回新的 Item 对象,例如Name: White, Score: 9, Count: 2
  3. Lists 集合按Count 排序,将Items 集合按ScoreCountName 排序。

我创建了以下 javascript 对象:

function List(title, items, count) {
    var self = this;
        self.Title = title;
        self.Count = count;
        self.Items = ko.observableArray(items);
}

function Item(name, count, score) {
    var self = this;
        self.Name = name;
        self.Count = count;
        self.Score = score;
}

我已经研究了各种方法,我打算用 underscore.js 来攻击这个任务,但我被报告在迭代数组时表现不佳而推迟了。

我预计JSON 文件会比我展示的示例大得多,因此性能很重要。

希望有些人可以提出实现我目标的最佳方法,并可能展示一个良好的起点。

提前致谢。

【问题讨论】:

    标签: javascript jquery arrays json knockout.js


    【解决方案1】:

    我在这个例子中使用Lo-Dash 2.2.1,但是你可以很容易地换入Underscore.js,因为他们的库_.each签名基本相同。

    Live Demo

    var collection = [{
      "title":"Things",
      "text":"1. Raindrops on roses 2. Whiskers on kittens 3. Bright copper kettles 4. Warm woolen mittens 5. Brown paper packages"
    },{
      "title":"Colors",
      "text":"1. White 2. Blue 3. Red 4. Yellow 5. Green"
    },{
      "title":"Animals",
      "text":"1. Dog 2. Rabbit 3. Cat 4. Squirrel 5. Duck"
    },{
      "title":"Colors",
      "text":"1. Red 2. Blue 3. Orange 4. Green 5. Purple"
    },{
      "title":"Animals",
      "text":"1. Bear 2. Bird 3. Duck 4. Squirrel 5. Rabbit"
    },{
      "title":"Colors",
      "text":"1. Yellow 2. White 3. Black 4. Brown 5. Blue"
    }];
    
    //Store all the collections in a single place.
    var collections = {}; 
    _.each(collection, function(item){
    
        //Does the collection exist?
        if(!collections[item.title]){
            //No? Add a new one
            collections[item.title] = {Title:'', Items: {} };    
        }
    
        //Split out the parts of the text by number period
        var parts = item.text.split(/[0-9]+\./); 
        if(parts.length > 0){
            parts.shift(); //remove the first entry in the array since it will be blank   
        }
    
        //Iterate over each part text we found
        _.each(parts, function(partName, i){
    
            partName = partName.trim(); //remove whitespace
    
            //Try to get an existing reference to the part
            var part = collections[item.title].Items[partName]; 
    
            //If the part doesn't exist
            if(!part){
    
                //Create a new one and add it to the collection
                part = { Score: 0, Count: 0 }; 
                collections[item.title].Items[partName] = part; 
            }
    
            //Increment the score by the ordinal position
            part.Score += i; 
    
            //Increment the count by 1
            part.Count++; 
        }); 
    });
    
    
    //Store the final array of collections here
    var finalData = []; 
    
    //Iterate over our current collection object
    _.each(collections, function(collection, i){
    
        var data = []; 
    
        //Convert the Items "hashtables"/objects into arrays
        for(var key in collection.Items){
    
            data.push({
                'Name': key,    
                'Score': collection.Items[key].Score, 
                'Count': collection.Items[key].Count
            }); 
    
        }
    
        collection.Items = data; //replace the Items object with the array
        collection.Count = data.length; //compute the current count. (Although you could always call Items.length)
        finalData.push(collection); //add the collection to the array.
    });
    
    console.log(finalData); 
    

    结果

    [
      {
        "Title": "Things",
        "Items": [
          {
            "Name": "Raindrops on roses",
            "Score": 0,
            "Count": 1
          },
          {
            "Name": "Whiskers on kittens",
            "Score": 1,
            "Count": 1
          },
          {
            "Name": "Bright copper kettles",
            "Score": 2,
            "Count": 1
          },
          {
            "Name": "Warm woolen mittens",
            "Score": 3,
            "Count": 1
          },
          {
            "Name": "Brown paper packages",
            "Score": 4,
            "Count": 1
          }
        ],
        "Count": 5
      },
      {
        "Title": "Colors",
        "Items": [
          {
            "Name": "White",
            "Score": 1,
            "Count": 2
          },
          {
            "Name": "Blue",
            "Score": 6,
            "Count": 3
          },
          {
            "Name": "Red",
            "Score": 2,
            "Count": 2
          },
          {
            "Name": "Yellow",
            "Score": 3,
            "Count": 2
          },
          {
            "Name": "Green",
            "Score": 7,
            "Count": 2
          },
          {
            "Name": "Orange",
            "Score": 2,
            "Count": 1
          },
          {
            "Name": "Purple",
            "Score": 4,
            "Count": 1
          },
          {
            "Name": "Black",
            "Score": 2,
            "Count": 1
          },
          {
            "Name": "Brown",
            "Score": 3,
            "Count": 1
          }
        ],
        "Count": 9
      },
      {
        "Title": "Animals",
        "Items": [
          {
            "Name": "Dog",
            "Score": 0,
            "Count": 1
          },
          {
            "Name": "Rabbit",
            "Score": 5,
            "Count": 2
          },
          {
            "Name": "Cat",
            "Score": 2,
            "Count": 1
          },
          {
            "Name": "Squirrel",
            "Score": 6,
            "Count": 2
          },
          {
            "Name": "Duck",
            "Score": 6,
            "Count": 2
          },
          {
            "Name": "Bear",
            "Score": 0,
            "Count": 1
          },
          {
            "Name": "Bird",
            "Score": 1,
            "Count": 1
          }
        ],
        "Count": 7
      }
    ]
    

    【讨论】:

    • 哇 - 很好的答案。非常感谢。我正在处理它,稍后会再次回复。
    • 你有机会解决它吗?我没有添加 ko. observableArray 组件,因为我认为您对转换例程更感兴趣,但它们应该非常容易添加。如果您有任何问题,请告诉我。
    • 嗨,布兰登,很抱歉回复晚了。实际上,我确实尝试将您的解决方案重新创建为纯淘汰赛(模型、ko.observableArrays 和 ko.utils),因为我需要合并更多功能,我怀疑淘汰赛 MVVM 会很好地适应这些功能。例如stackoverflow.com/questions/22003718/… 在回复您的问题之前,我希望能明确回答这个问题。就像我说的那样,性能是最重要的,所以如果 lo-dash 的 _each 比淘汰赛的 ArrayForEach 快(例如),我会这样做。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-25
    • 2013-05-21
    • 2019-06-04
    • 2021-10-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多