使用 jQuery 根据值对 JSON 数组进行排序
Posted
技术标签:
【中文标题】使用 jQuery 根据值对 JSON 数组进行排序【英文标题】:Sort JSON array based on value with jQuery 【发布时间】:2013-08-31 15:48:16 【问题描述】:我有两个下拉选择下拉菜单:一个用于区域,一个用于所选区域中的城市。结果由 AJAX 加载,在我的响应中,我得到了 JSON 数组中的所有城市:
1709: "Geertruidenberg",
1710: "Netersel",
1711: "Macharen",
1712: "Beers",
1713: "Hank",
1714: "Oudemolen",
1715: "Nistelrode"
我正在使用这个小插件来加载选择下拉列表中的数据:
(function($, window)
$.fn.replaceOptions = function(options)
var self, $option;
this.empty();
self = this;
$.each(options, function(index, option)
$option = $("<option></option>")
.attr("value", index)
.text(option);
self.append($option);
);
;
)(jQuery, window);
还有这段 javascript 来做 AJAX 请求:
$('select#Profile_regionId').change(function()
$.post('/ajax/getcities', regionid: $(this).val(), function(data)
//console.log(data.cities);
$("select#Profile_cityId").replaceOptions(data.cities);
, 'json');
);
一切正常,除了城市下拉菜单自动按 JSON 数组键排序。我尝试为此使用 sort() 方法,但它不起作用,因为它是一个对象而不是数组。然后我尝试创建一个数组:
var values = [];
$.each(data.cities, function(index,value))
values[index] = value;
但由于某种原因,下拉列表会从 1 填充到该城市的第一个找到的 id(数组的键),我不知道它为什么这样做(数组本身看起来不错)。
我如何对事物进行排序,以便我的城市在下拉列表中按字母顺序排列?
【问题讨论】:
请注意,对象的顺序永远无法保证,因此您可能应该在进行排序时使用正确的数组。 我知道,使用 .sort() 对对象进行排序甚至是不可能的,这就是我将其转换为正确的 javascript 数组的原因,但它从 1 填充到只有键没有值的城市,所以在城市出现之前我会得到一堆空的 【参考方案1】:需要转换成数组才能排序。假设这是您的对象。请注意,我将其重新排列为未排序,以证明这是可行的。
originalData =
1712: "Beers",
1709: "Geertruidenberg",
1710: "Netersel",
1713: "Hank",
1714: "Oudemolen",
1711: "Macharen",
1715: "Nistelrode"
;
现在要创建一个数组版本,我们需要创建一个数组,并将对象插入其中。我称这些键为“年”。请注意,我们在键上调用 parseInt。 JavaScript 中的键(数组除外)总是字符串。例如,foo: "bar"
有一个字符串键“foo”。这也适用于数字键。
var dataArray = [];
for (year in originalData)
var word = originalData[year];
dataArray.push(year: parseInt(year), word: word);
现在我们的数据可能无法排序,因此我们手动对其进行排序。请注意,这是区分大小写的排序。例如,“Qux”出现在“foo”之前。
dataArray.sort(function(a, b)
if (a.word < b.word) return -1;
if (b.word < a.word) return 1;
return 0;
);
该函数现在只是从我们的数组中提取 option.year 和 option.word。
$.fn.replaceOptions = function(options)
var self, $option;
this.empty();
self = this;
$.each(options, function(index, option)
$option = $("<option></option>")
.attr("value", option.year)
.text(option.word);
self.append($option);
);
;
然后你最终使用插件,传递数组。如果最适合您,您可以将所有这些代码放入插件中。
$('#mylist').replaceOptions(dataArray);
fiddle
【讨论】:
【参考方案2】:这将做你想做的事并处理空的 ids/undefined 值:
var data =
1709: "Geertruidenberg",
1710: "Netersel",
1711: "Macharen",
1712: "Beers",
1713: "Hank",
1714: "Oudemolen",
1715: "Nistelrode"
;
var values = [];
$.each(data, function(index, value)
values[index] = value;
);
values.sort();
$.each(values, function(index, value)
if(value != undefined)
$("#Profile_cityId").append("<option>"+ value +"</option");
);
只需用您自己的函数替换我输入的附加内容,因为 jsFiddle 给我使用它带来了麻烦。 演示:http://jsfiddle.net/R4jBT/3/
【讨论】:
【参考方案3】:这就是我的做法。我假设您收到的 AJAX 响应如下:
results: [
year: 1709, city: "Geertruidenberg",
year: 1710, city: "Netersel",
year: ..., city: ...
]
而且,在标准 AJAX 调用中,您可以像这样在 success
函数中运行它们:
success: function(data)
var results = data.results;
if (results.length > 0)
for (i=0; i < results.length; i++)
dataArrayOrig.push(
"id" : results[i].year,
"label" : results[i].city
);
,
我看到你说你是这样打电话的:
$.post('/ajax/getcities', regionid: $(this).val(), function(data)
//console.log(data.cities);
$("select#Profile_cityId").replaceOptions(data.cities);, 'json');
您没有对data
进行任何测试以查看它是否有结果(例如if (data.length > 0) ...
),您需要将这些结果推送到一个保持原始状态的原始数组和另一个可以排序的数组,然后是可以将原始年份返回到标签的最后一个,然后下拉可以接收。
如果你按照我上面显示的那样做,你可以将我给的行整合到function(data) ...
区域。
在push
到dataArrayOrig
对象之后,您可以推送到一个新的数组以用于排序,使用比较函数来确定标签(城市)应该位于前一个条目之前还是之后:
var results = data.results;
if (results.length > 0)
for (i=0; i < results.length; i++)
dataArrayOrig.push(
"id" : results[i].year,
"label" : results[i].city
);
dataArraySorting.push(
"id" : results[i].year,
"label" : results[i].city
);
dataArraySorting.sort(compare);
JSON.stringify(dataArraySorting); // sorted cities, but will be mismatched to the years
比较函数:
function compare (a, b)
if (a.label < b.label)
return -1;
if (b.label < a.label)
return 1;
return 0;
);
您也可以内联执行此操作:
dataArraySorting.sort(function(a, b)
if (a.label < b.label) return -1;
if (b.label < a.label) return 1;
return 0;
);
我更喜欢函数方法,因为它可以重复使用。我们马上就会看到它的用处。
对于您的数组,将它们声明在顶部,在您的函数之前:
var dataArrayOrig = [];
var dataArraySorting = [];
var dataArraySorted = [];
因此,在遍历结果的循环之后,启动另一个遍历“排序”数组的循环,并将其标签与我们推送到的原始数组中的标签进行比较,然后取出原始 ID(年份):
for (var j=0; j < dataArraySorting.length; j++)
for (var k=0; k < dataArrayOrig.length; k++)
if (dataArraySorting[j].label == dataArrayOrig[k].label)
dataArraySorted.push(
"id" : dataArrayOrig[k].id,
"label" : dataArraySorting[j].label
);
console.log("Sorted ID: " + dataArrayOrig[k].id + ", Sorted label: " + dataArraySorting[j].label);
dataArraySorted.sort(compare);
JSON.stringify(dataArraySorted); // array of sorted cities, matched to year
您将继续像往常一样将 dataArraySorted
数组应用到您的下拉列表中。我测试了我是否从原始 AJAX 调用中获得了超过 0 个项目,然后我使用数组属性名称中的 id
和 label
附加了选项:
if (dataArraySorted.length > 0)
$.each(dataArraySorted, function()
$("#combobox").empty().append($("<option></option>").val(this['id']).html(this['label'));
);
JSFiddle 与结果。
【讨论】:
以上是关于使用 jQuery 根据值对 JSON 数组进行排序的主要内容,如果未能解决你的问题,请参考以下文章
在 JavaScript 中使用空值对 JSON 数组进行排序