【问题标题】:Converting JSON Object to Array for Sorting Without Losing Keys/Indexes将 JSON 对象转换为数组以便在不丢失键/索引的情况下进行排序
【发布时间】:2016-02-20 21:05:53
【问题描述】:

很抱歉有类似的主题,但我无法解决这个问题。我有一个 JSON 对象,其中包含键和值(表示文件 ID 和文件名)。由于 JS 对象无法排序,我需要转换为数组,按值(即文件名)排序,而不是按键(即文件 ID)排序。我可以完成所有这一切,除非在转换为数组时,我丢失了我的键/文件 ID(例如,110、111、112)并且它们被替换为默认的数组键(0、1、2 等)。

// Assign object to a var
$obj_win_top_get_files = window.top.<?php echo $_GET['files']; ?>;

通过console.log查看对象,

console.log('checked_boxes', $obj_win_top_get_files);

我明白了:

对象{110:“013_904_general.docx”,111:“013_902_info.docx”,112:“013_120_list.docx”}

// Sort JSON object by file name ("value") rather than by id ("key")
// Create an array first since JS object is NOT sortable
arr_ids_filenames = new Array(); 

// Loop thru JS object to populate new array so it can be subsequently sorted
$.each($obj_win_top_get_files, function (key, value) {
    console.log(key, value); 
    // Populate array
    arr_ids_filenames[key] = value;
});

// Sort array by values
arr_ids_filenames.sort();
// THIS IS WHERE I AM LOSING THE FILE IDs (keys)
$.each(arr_ids_filenames, function (key, value) {
    // Array may contain keys/IDs with no values/file names so make sure there is a value
    if(value){
        console.log(key, value); 
        $the_ul.append('<li id="chk_file_' + key + '">' + value + '</li>');
    }
});

一切正常,除了它们的键不是文件 ID (110,111,112),它们是默认的数组键 (0,1,2)。这是 $.each() 中我做的不正确的东西。我很接近,但无法解决这个问题。任何建议将不胜感激。

【问题讨论】:

  • 在没有任何完整性检查的情况下打印$_GET['files'] 是一个非常糟糕的主意。 XSS、CSRF 等
  • 如您所说,您无法对对象进行排序。如果在 PHP 中将其设为包含对象的数组,则可以使用 Array.sort 在 JS 中的子属性上对其进行排序
  • 感谢 Rudie 的反馈。 GET var 是通过 AJAX 从我的其他页面之一发送的。
  • 你不知道 GET 变量是如何被发送的,这就是黑客的问题,他们不会做你想做的事。如果您的网站有会话/cookie,它们将被劫持。打印时总是 html/js 对所有内容进行编码。永远不要相信输入。

标签: javascript arrays json sorting object


【解决方案1】:

更新的解决方案:

我提供的原始解决方案在 IE11 中不起作用。控制台返回“SCRIPT1003”错误,经过进一步研究,我提出了这个 SO 问题:JavaScript in IE11 giving me script error 1003

IE11 不支持 ES6 密钥对速记。考虑到这一点,更新后的代码应如下所示:

var arr_ids_filenames  = [];

// convert your file list into an array of objects
$.each($obj_win_top_get_files, function(key, name) {
    // use key:pair format
    arr_ids_filenames.push({
        key: key, 
        name: name
    });
});

// sort by file name (and not by key/id)
arr_ids_filenames.sort(function(a, b) {
    return ((a.name < b.name) ? -1 : ((a.name > b.name) ? 1 : 0));
});

// add items to list   
$.each(arr_ids_filenames, function(index, file) {
    $the_ul.append('<li id="chk_file_' + file.key + '">' + file.name + '</li>')
});

查看实际代码:https://jsfiddle.net/7y7qps88/53/

【讨论】:

  • 谢谢 dhira!这就是解决方案!非常感谢。
  • 太棒了!很高兴能提供帮助。
  • 首先,非常感谢您的帖子和对我的问题的解决方案。不幸的是,代码甚至你的 jsfiddle 只能在 Chrome 中工作,在 IE 11 中,列表元素不会呈现,并且控制台会显示“script5 access denied”错误。任何建议表示赞赏。
  • @12AX7 查看我更新的 IE 修复帖子。在 Windows 8 上测试这是 IE11。如果您遇到任何其他问题,请告诉我。
  • 谢谢@Skippr!这是让它在 IE 11 中运行的解决方案。感谢您的时间和专业知识!
【解决方案2】:

创建一个包含 2 个项目的数组数组。键和对象。现在你有一个像这样的数组:

[
  [originalKey, obj],
  [originalKey, obj],
  [originalKey, obj]
]

然后使用自定义排序功能:

arr_ids_filenames.sort(function(a,b){ return a[1] - b[1] });

(注意:我假设您的对象只是整数,如果不这样做是为了排序)

arr_ids_filenames.sort(function(a, b) {
  a = a[1]; // now a points to object 1
  b = b[1]; // now b points to object 2
  if (a is less than b by some ordering criterion) {
    return -1;
  }
  if (a is greater than b by the ordering criterion) {
    return 1;
  }
  // a must be equal to b
  return 0;
});

大家一起:

// Sort JSON object by file name ("value") rather than by id ("key")
// Create an array first since JS object is NOT sortable
arr_ids_filenames = new Array(); 

// Loop thru JS object to populate new array so it can be subsequently sorted
var i = 0;
$.each($obj_win_top_get_files, function (key, value) {
    console.log(key, value); 
    // Populate array
    arr_ids_filenames[i++] = [key,value];
});

// Sort array by values
arr_ids_filenames.sort(function(a,b){ return a[1] - b[1] });
// THIS IS WHERE I AM LOSING THE FILE IDs (keys)
$.each(arr_ids_filenames, function (i, v) {
    // Array may contain keys/IDs with no values/file names so make sure there is a value
    if(v[0]){
        var key = v[0];
        var value = v[1];
        $the_ul.append('<li id="chk_file_' + key + '">' + value + '</li>');
    }
});

【讨论】:

  • b[2] 应该是b[1]。
  • @Macmee 不错的解决方案,+1。
【解决方案3】:

通过将对象添加到数组中的索引 大于 比数组的长度(这是您对 arr_ids_filenames[key] = value 所做的)所有先前(在该索引之前)未初始化的元素都会被初始化到undefined。

例如,对空数组执行此操作:

arr_ids_filenames[110] = 'ANYSTRING'

你得到:

arr_ids_filenames[0] = undefined;
arr_ids_filenames[1] = undefined;
// ...
arr_ids_filenames[110] = 'ANYSTRING';

现在在你排序之后,因为:

 'ANYSTRING' > undefined // is false
 'ANYSTRING' < undefined // is false

您的值是最小值,因此存储在索引0 处,其后是所有undefineds。您接下来的所有存储尝试都遵循此模式。

因此,您最终得到一个包含 112 个元素的数组,您的字符串位于前 3 个位置。解决这个问题的一种方法是创建一个对象:

var file = {
    id: '',
    name: ''
};

然后,对于每个文件,将该对象插入到一个新数组中:

// Loop thru JS object to populate new array so it can be subsequently sorted
$.each($obj_win_top_get_files, function (key, value) {
    console.log(key, value); 
    // Populate array
    var file = {
        id: key,
        name: value
    };
    arr_ids_filenames.push(file);
});

按文件名对数组进行排序(使用比较器):

arr_ids_filenames.sort(function(a, b) { return a.name < b.name; });

最后将它们插入到 DOM 中:

$.each(arr_ids_filenames, function(idx, file) {
  // Array may contain keys/IDs with no values/file names so make sure there is a value
  if (file.name) {
    var key = file.id;
    var value = file.name;
    $the_ul.append('<li id="chk_file_' + key + '">' + value + '</li>');
  }
});

这是一个运行示例:

var $obj_win_top_get_files = {
  110: "013_904_general.docx",
  111: "013_902_info.docx",
  112: "013_120_list.docx"
}

var arr_ids_filenames = [];
// Loop thru JS object to populate new array so it can be subsequently sorted
$.each($obj_win_top_get_files, function(key, value) {
  // Populate array
  arr_ids_filenames.push({
    id: key,
    name: value
  });
});

// Sort the array by file name (by using a comparator):
arr_ids_filenames.sort(function(a, b) {
  return a.name < b.name;
});

console.log('sort: ' + JSON.stringify(arr_ids_filenames));

// And finally insert them in the DOM:
var $the_ul = $('ul');
$.each(arr_ids_filenames, function(idx, file) {
  if (file.name) {
    var key = file.id;
    var value = file.name;
    console.log('here');
    $the_ul.append('<li id="chk_file_' + key + '">' + value + '</li>');
  }
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<ul></ul>

【讨论】:

  • 非常感谢 nem 的详细回答。我现在非常接近。该数组按 ID 排序,我需要按文件名排序。
  • 标签中的值也是“未定义”。有什么建议吗?
  • 没问题,很高兴为您提供帮助!我更新了代码以按文件名而不是 id 排序,我在此处发布的运行示例代码显示了如何将正确的值放入 li 标签中。
  • Nem,再次感谢,这非常接近。唯一不起作用的是保留文件 ID。 'key' 变量未定义。 $.each(arr_ids_filenames, function(idx, file) { if (file.name) { var key = file.key; var value = file.name; console.log('here'); $the_ul.append('' + value + ''); } });
  • 我刚刚注意到一个小错误。在最后一个.each 中,我访问了file.key,应该已经访问了file.id。现在已修复,请查看更新的答案/sn-p,希望对您有所帮助!
  • 是的,这修复了您的解决方案,我确认它有效。再次感谢您的宝贵时间!
  • 猜你喜欢
    相关资源
    最近更新 更多
    热门标签