以特定方式重新排列 JSON 数据

Posted

技术标签:

【中文标题】以特定方式重新排列 JSON 数据【英文标题】:Rearrange JSON data in a specific way 【发布时间】:2020-07-16 17:37:29 【问题描述】:

我有一个类似于以下内容的 JSON 数据集:

[
  
    "name": "Concert 1",
    "sponsors": [
      
        "name": "Woolworths",
        "location": "Mildura"
      ,
      
        "name": "Coles",
        "location": "Melbourne"
      ,
      
        "name": "Metricon",
        "location": "Wagga Wagga"
      
    ]
  ,
  
    "name": "Concert 2",
    "sponsors": [
      
        "name": "Metricon",
        "location": "Albert Park"
      ,
      
        "name": "Woolworths",
        "location": "Melbourne"
      ,
      
        "name": "ALDI",
        "location": "Bendigo"
      
    ]
  ,
  
    "name": "Concert 3",
    "sponsors": [
      
        "name": "Holcim",
        "location": "Bendigo"
      ,
      
        "name": "Westpac",
        "location": "Melbourne"
      ,
      
        "name": "Coles",
        "location": "Mildura"
      
    ]
  
]

我想在网页上以以下格式显示此 JSON 输出:

Location X
   Sponsor X
      Concert 1
      Concert 2
      -------
   Sponsor Y
      Concert 1
Location Y
   Sponsor Y
      Concert 1
      Concert 2
      ------
   --------

基本上,我必须在顶层显示 Location 并将其他元素显示为子元素,换句话说,将 JSON 数据集颠倒过来。

到目前为止,我已经尝试使用 VueJS 计算属性循环遍历 JSON 文件,但仍然没有运气。有人可以告诉我如何解决这个问题吗?

如果我在这里没有使用正确的技术术语,我很抱歉,因为我不确定当我们显示这样的内容时我们会调用什么。

【问题讨论】:

请贴出你目前拥有的JS代码。 欢迎来到 Stack Overflow!请使用tour(您将获得徽章!)并通读help center,尤其是How do I ask a good question? 您最好的选择是进行研究,search 以获取有关 SO 的相关主题,然后试一试.如果您在进行更多研究和搜索后遇到困难并且无法摆脱困境,请发布您的尝试minimal reproducible example,并具体说明您卡在哪里。人们会很乐意提供帮助。 【参考方案1】:

数据的转换方法如下:

const data = [
    "name": "Concert 1",
    "sponsors": [
      "name": "Woolworths","location": "Melbourne",
      "name": "Coles","location": "Melbourne",
      "name": "Metricon","location": "Wagga Wagga"
    ]
  ,
  
    "name": "Concert 2",
    "sponsors": [
      "name": "Metricon","location": "Albert Park",
      "name": "Woolworths","location": "Melbourne",
      "name": "ALDI","location": "Bendigo"
    ]
  ,
  
    "name": "Concert 3",
    "sponsors": [
      "name": "Holcim","location": "Bendigo",
      "name": "Westpac","location": "Melbourne",
      "name": "Coles","location": "Mildura"
    ]
  
];

const byLocation = data.reduce((r, con) => (con.sponsors.forEach(sp => 
  if (!r[sp.location]) r[sp.location] = ;
  if (!r[sp.location][sp.name]) r[sp.location][sp.name] = [];
  r[sp.location][sp.name].push(con.name);
), r), );

console.log(byLocation);

以上解释:

要转换初始的data Array 的音乐会

[
  concert,
  concert,
  // ...
]

放入对象 - 所有属性名称(位置)都是唯一的


  "location name 1": ,
  "location name 2": ,
  // ...

第一个想法是使用Array.prototype.reduce() MDN

const byLocation = data.reduce((resultObject, concert) => 
  // Insert concert data into resultObject here
  return resultObject; // Return the Object for the next iteration
, ); // <<  is the resultObject

为了简短起见,进行了一些重命名,通过使用 箭头函数的隐式返回(没有包装花括号),我们可以将上面的内容转换/缩短为:

const byLocation = data.reduce((r, con) => (/*Insert con data into r*/, r), );

所以con 是迭代Concert,r 是我们需要构建的Resulting final Object。 让我们通过forEach 填充r 对象-ing con.sponsors 数组

  con.sponsors.forEach(sp =>  // sp is the iterating Sponsor
    // If r["location name"] does not exists, create it as empty object
    if (!r[sp.location]) r[sp.location] = ;
    // If r["location name"]["Sponsor name"] does not exists, create it
    // as an empty array
    if (!r[sp.location][sp.name]) r[sp.location][sp.name] = [];
    // Finally push the Concert name into that array.
    r[sp.location][sp.name].push(con.name);
  )

如果概念太高级,也可以这样写:

const data = [
    "name": "Concert 1",
    "sponsors": [
      "name": "Woolworths","location": "Melbourne",
      "name": "Coles","location": "Melbourne",
      "name": "Metricon","location": "Wagga Wagga"
    ]
  ,
  
    "name": "Concert 2",
    "sponsors": [
      "name": "Metricon","location": "Albert Park",
      "name": "Woolworths","location": "Melbourne",
      "name": "ALDI","location": "Bendigo"
    ]
  ,
  
    "name": "Concert 3",
    "sponsors": [
      "name": "Holcim","location": "Bendigo",
      "name": "Westpac","location": "Melbourne",
      "name": "Coles","location": "Mildura"
    ]
  
];

const byLocation = ; // The resulting object of unique Locations

data.forEach((concert) => 

  const sponsors = concert.sponsors;
  
  sponsors.forEach((sponsor) => 
  
    if (!byLocation.hasOwnProperty(sponsor.location)) 
        byLocation[sponsor.location] = ;
    
    
    if (!byLocation[sponsor.location].hasOwnProperty(sponsor.name)) 
        byLocation[sponsor.location][sponsor.name] = [];
    
    
    byLocation[sponsor.location][sponsor.name].push(concert.name);
  );
  
);

console.log(byLocation);

javascript 显示 &lt;ul id="list"&gt;&lt;/ul&gt; 内的数据:

const html = Object.entries(byLocation).reduce((h, [location, ob]) => 
  h += `<li>$location<ul>`;
  Object.entries(ob).forEach(([sponsor, concerts]) => 
    h += `<li>$sponsor
            <ul>
              <li>$concerts.join('</li><li>')</li>
            </ul>
          </li>`;
  ); 
  h += `</ul></li>`;
  return h
, ''); 

document.querySelector('#list').insertAdjacentHTML('beforeend', html);

【讨论】:

嘿 Roko,非常感谢您的回答,这救了我。如果我要求您解释您编写的代码,会不会太过分了?这一切都很好,就像一个魅力,但我想了解你在这里究竟做了什么,特别是reduce()的使用。如果你能放一些 cmets 那就太好了,它会帮助我和接下来寻找这样的东西的人。再次感谢。 @Dynamdilshan 下面是 reduce 的语法:array.reduce(function(total, currentValue, currentIndex, arr), initialValue)。所以,Roko 正在做的是:r:reduce 的“total”,这意味着最后将返回的值。 con:当前演唱会。然后,他遍历每场音乐会的赞助商,并在 r 对象上创建一个条目(如果尚不存在),并且与赞助商名称相同。最后,initialValuerreduce 函数的第一次迭代中的值,在这种情况下是一个空对象()。希望这会有所帮助。 谢谢@tintef 非常感谢您的帮助!我还添加了一些解释。 嗨@RokoC.Buljan,如果我来回处理这个问题,我很抱歉。我对这个解决方案有最后一个问题。如果我想按字母顺序对所有这些条目进行排序,我该怎么做?你能指点我正确的方向吗?。 @Dynamdilshan 请提出一个新问题,如果有超出此范围的内容。【参考方案2】:

一个简单的解决方案是:

将你的 json 数据传递给你的数据对象中的 vue

添加一个计算属性“formattedData”,并提供一个函数,将 json 数据格式化为您需要的格式。

在模板中使用此计算属性来呈现数据。

我将大致说明您可以做什么:

var concertData = [
    
        "name": "Concert 1",
        "sponsors": [
            
                "name": "Woolworths",
                "location": "Mildura"
            ,
            
                "name": "Coles",
                "location": "Melbourne"
            ,
            
                "name": "Metricon",
                "location": "Wagga Wagga"
            
        ]
    ,
    
        "name": "Concert 2",
        "sponsors": [
            
                "name": "Metricon",
                "location": "Albert Park"
            ,
            
                "name": "Woolworths",
                "location": "Melbourne"
            ,
            
                "name": "ALDI",
                "location": "Bendigo"
            
        ]
    ,
    
        "name": "Concert 3",
        "sponsors": [
            
                "name": "Holcim",
                "location": "Bendigo"
            ,
            
                "name": "Westpac",
                "location": "Melbourne"
            ,
            
                "name": "Coles",
                "location": "Mildura"
            
        ]
    
];

new Vue(
  data: 
    concerts: concertData // pass your concert json here
  ,
    computed: 
        formattedData: function () 
            var formattedData = new Map();
            this.concerts.forEach(function (item) 
                item.sponsors.forEach(function (sponsor) 
                    if (!formattedData.has(sponsor.location)) 
                        formattedData.set(sponsor.location, new Map());
                    

                    if (!formattedData.get(sponsor.location).has(sponsor.name)) 
                        formattedData.get(sponsor.location).set(sponsor.name, []);
                    

                    formattedData.get(sponsor.location).get(sponsor.name).push(item.name);
                )
            );

            return formattedData;
        
    ,
    render: function(h) 
        // loop over this.formattedData to paint the display
    

).$mount("#app");

【讨论】:

以上是关于以特定方式重新排列 JSON 数据的主要内容,如果未能解决你的问题,请参考以下文章

JSON请求后以编程方式TableView不会重新加载数据

Swift 2.0 - 按子数组重新排列 JSON 对象

R - 根据模式重新排列数据[重复]

如何以编程方式重新排序primefaces数据表中的列

如何使用 jq 重新格式化 json 中的特定数据

重新排列单词以在一行中容纳最多单词并使用 Java 创建更少的行数