ด้วยBackbone.jsฉันได้ตั้งค่าคอลเลคชันด้วยฟังก์ชันเปรียบเทียบ มันจัดเรียงแบบจำลองได้ดี แต่ฉันต้องการกลับลำดับ
ฉันจะจัดเรียงแบบจำลองจากมากไปหาน้อยได้อย่างไร
ด้วยBackbone.jsฉันได้ตั้งค่าคอลเลคชันด้วยฟังก์ชันเปรียบเทียบ มันจัดเรียงแบบจำลองได้ดี แต่ฉันต้องการกลับลำดับ
ฉันจะจัดเรียงแบบจำลองจากมากไปหาน้อยได้อย่างไร
คำตอบ:
คุณสามารถคืนค่าลบจากตัวเปรียบเทียบได้ ตัวอย่างเช่นหากเราใช้ตัวอย่างจากไซต์ของ Backbone และต้องการย้อนลำดับจะมีลักษณะดังนี้:
var Chapter = Backbone.Model;
var chapters = new Backbone.Collection;
chapters.comparator = function(chapter) {
return -chapter.get("page"); // Note the minus!
};
chapters.add(new Chapter({page: 9, title: "The End"}));
chapters.add(new Chapter({page: 5, title: "The Middle"}));
chapters.add(new Chapter({page: 1, title: "The Beginning"}));
alert(chapters.pluck('title'));
โดยส่วนตัวแล้วฉันไม่ค่อยพอใจกับวิธีแก้ปัญหาใด ๆ ที่ให้ไว้ที่นี่:
โซลูชันการคูณด้วย -1 ล้มเหลวในการทำงานเมื่อประเภทการจัดเรียงไม่ใช่ตัวเลข แม้ว่าจะมีวิธีการต่างๆ (โดยการเรียกDate.getTime()
เช่น) กรณีเหล่านี้เป็นกรณีเฉพาะ ฉันต้องการวิธีทั่วไปในการย้อนกลับทิศทางของการเรียงลำดับใด ๆ โดยไม่ต้องกังวลเกี่ยวกับประเภทของฟิลด์ที่ระบุ
สำหรับโซลูชันสตริงการสร้างสตริงทีละอักขระดูเหมือนว่าเป็นคอขวดของประสิทธิภาพโดยเฉพาะอย่างยิ่งเมื่อใช้คอลเลคชันขนาดใหญ่ (หรือสตริงฟิลด์การเรียงลำดับขนาดใหญ่)
นี่คือโซลูชันที่ใช้งานได้ดีสำหรับฟิลด์สตริงวันที่และตัวเลข:
ประการแรกประกาศตัวเปรียบเทียบที่จะย้อนกลับผลลัพธ์ของผลลัพธ์ของฟังก์ชัน sortBy ดังนี้:
function reverseSortBy(sortByFunction) {
return function(left, right) {
var l = sortByFunction(left);
var r = sortByFunction(right);
if (l === void 0) return -1;
if (r === void 0) return 1;
return l < r ? 1 : l > r ? -1 : 0;
};
}
ตอนนี้หากคุณต้องการกลับทิศทางของการจัดเรียงสิ่งที่เราต้องทำคือ:
var Chapter = Backbone.Model;
var chapters = new Backbone.Collection;
// Your normal sortBy function
chapters.comparator = function(chapter) {
return chapter.get("title");
};
// If you want to reverse the direction of the sort, apply
// the reverseSortBy function.
// Assuming the reverse flag is kept in a boolean var called reverseDirection
if(reverseDirection) {
chapters.comparator = reverseSortBy(chapters.comparator);
}
chapters.add(new Chapter({page: 9, title: "The End"}));
chapters.add(new Chapter({page: 5, title: "The Middle"}));
chapters.add(new Chapter({page: 1, title: "The Beginning"}));
alert(chapters.pluck('title'));
เหตุผลนี้ทำงานได้Backbone.Collection.sort
แตกต่างกันถ้าฟังก์ชัน sort มีสองอาร์กิวเมนต์ Array.sort
ในกรณีนี้มันจะทำงานในลักษณะเดียวกับที่เปรียบเทียบผ่านเข้ามา วิธีการแก้ปัญหานี้ทำงานโดยการปรับฟังก์ชัน sortBy อาร์กิวเมนต์เดียวเป็นตัวเปรียบเทียบอาร์กิวเมนต์สองตัวและกลับผลลัพธ์
ตัวเปรียบเทียบคอลเล็กชันของ Backbone.js อาศัยวิธี Underscore.js _.sortBy วิธีการใช้ sortBy จะลงเอยด้วยการ "ตัด" javascript .sort () ในลักษณะที่ทำให้การเรียงลำดับสตริงย้อนกลับทำได้ยาก การปฏิเสธอย่างง่ายของสตริงจะจบลงด้วยการส่งคืน NaN และหยุดการเรียงลำดับ
หากคุณต้องการทำการเรียงลำดับย้อนกลับด้วย Strings เช่นการเรียงลำดับตัวอักษรย้อนกลับนี่เป็นวิธีที่แฮ็กจริงๆ:
comparator: function (Model) {
var str = Model.get("name");
str = str.toLowerCase();
str = str.split("");
str = _.map(str, function(letter) {
return String.fromCharCode(-(letter.charCodeAt(0)));
});
return str;
}
มันไม่ได้สวยอะไร แต่มันคือ "ตัวลบสตริง" หากคุณไม่มีคุณสมบัติใด ๆ กับการแก้ไขประเภทออบเจ็กต์เนทีฟในจาวาสคริปต์คุณสามารถทำให้โค้ดของคุณชัดเจนขึ้นได้โดยการแยกตัวลบสตริงและเพิ่มเป็นวิธีการใน String.Prototype อย่างไรก็ตามคุณอาจต้องการทำสิ่งนี้ก็ต่อเมื่อคุณรู้ว่าคุณกำลังทำอะไรอยู่เนื่องจากการแก้ไขประเภทวัตถุดั้งเดิมในจาวาสคริปต์อาจส่งผลที่ไม่คาดคิดได้
วิธีแก้ปัญหาของฉันคือการย้อนกลับผลลัพธ์หลังจากเรียงลำดับ
เพื่อป้องกันการแสดงผลซ้ำสองครั้งในการจัดเรียงครั้งแรกโดยไม่มีการโต้ตอบจากนั้นทริกเกอร์ 'รีเซ็ต'
collections.sort({silent:true})
collections.models = collections.models.reverse();
collections.trigger('reset', collections, {});
-Date.getTime()
โดยอาจมีการแฮ็กเพิ่มเติมหากคุณเชื่อว่าวันที่ในระบบของคุณจะข้ามยุคยูนิกซ์ สำหรับการเรียงตามตัวอักษรให้ดูที่คำตอบของ Andrew ด้านบน
ปรับเปลี่ยนฟังก์ชันตัวเปรียบเทียบของคุณเพื่อส่งกลับค่าโพรโพลิชันแบบย้อนกลับแทนการส่งคืนข้อมูลที่คุณอยู่ในปัจจุบัน โค้ดบางส่วนจาก: http://documentcloud.github.com/backbone/#Collection-comparator
ตัวอย่าง:
var Chapter = Backbone.Model;
var chapters = new Backbone.Collection;
/* Method 1: This sorts by page number */
chapters.comparator = function(chapter) {
return chapter.get("page");
};
/* Method 2: This sorts by page number in reverse */
chapters.comparator = function(chapter) {
return -chapter.get("page");
};
chapters.add(new Chapter({page: 9, title: "The End"}));
chapters.add(new Chapter({page: 5, title: "The Middle"}));
chapters.add(new Chapter({page: 1, title: "The Beginning"}));
สิ่งต่อไปนี้ใช้ได้ผลดีสำหรับฉัน:
comparator: function(a, b) {
// Optional call if you want case insensitive
name1 = a.get('name').toLowerCase();
name2 = b.get('name').toLowerCase();
if name1 < name2
ret = -1;
else if name1 > name2
ret = 1;
else
ret = 0;
if this.sort_dir === "desc"
ret = -ret
return ret;
}
collection.sort_dir = "asc";
collection.sort(); // returns collection in ascending order
collection.sort_dir = "desc";
collection.sort(); // returns collection in descending order
ฉันอ่านบางส่วนที่ฟังก์ชันเปรียบเทียบ Backbone ใช้หรือเลียนแบบฟังก์ชัน JavaScript Array.prototype.sort () ซึ่งหมายความว่าจะใช้ 1, -1 หรือ 0 เพื่อตัดสินใจเกี่ยวกับลำดับการจัดเรียงของแต่ละรุ่นในคอลเล็กชัน สิ่งนี้อัปเดตอย่างต่อเนื่องและคอลเลคชันจะอยู่ในลำดับที่ถูกต้องตามตัวเปรียบเทียบ
ข้อมูลเกี่ยวกับ Array.prototype.sort () สามารถพบได้ที่นี่: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort?redirectlocale=en-US&redirectslug=JavaScript% 2FReference% 2FGlobal_Objects% 2FArray% 2Fsort
คำตอบจำนวนมากสำหรับคำถามนี้เพียงแค่ย้อนลำดับก่อนที่จะส่งไปที่หน้า ไม่เหมาะอย่างยิ่ง
การใช้บทความข้างต้นเกี่ยวกับ Mozilla เป็นแนวทางฉันสามารถจัดเรียงคอลเลคชันของฉันในลำดับย้อนกลับได้โดยใช้รหัสต่อไปนี้จากนั้นเราก็แสดงคอลเลกชันเป็นหน้าตามลำดับปัจจุบันและเราสามารถใช้แฟล็ก (reverseSortDirection) เพื่อย้อนกลับคำสั่ง .
//Assuming this or similar will be in your Backbone.Collection.
sortKey: 'id', //The field name of the item in your collection
reverseSortDirection: false,
comparator: function(a, b) {
var sampleDataA = a.get(this.sortKey),
sampleDataB = b.get(this.sortKey);
if (this.reverseSortDirection) {
if (sampleDataA > sampleDataB) { return -1; }
if (sampleDataB > sampleDataA) { return 1; }
return 0;
} else {
if (sampleDataA < sampleDataB) { return -1; }
if (sampleDataB < sampleDataA) { return 1; }
return 0;
}
},
ตัวเปรียบเทียบยกเว้นสองรุ่นในการเปลี่ยนแปลงคอลเลกชันหรือโมเดลที่ฟังก์ชันตัวเปรียบเทียบทำงานและเปลี่ยนลำดับของคอลเลกชัน
ฉันได้ทดสอบแนวทางนี้กับ Numbers และ Strings แล้วและดูเหมือนว่าจะทำงานได้ดีสำหรับฉัน
ฉันหวังว่าคำตอบนี้จะช่วยได้จริง ๆ เนื่องจากฉันต่อสู้กับปัญหานี้มาหลายครั้งและมักจะจบลงด้วยการใช้วิธีแก้ปัญหา
sortKey
และreverseSortDirection
และโทร.sort()
จากมุมมองใด ๆ ที่มีการจัดการในคอลเลกชัน ง่ายกว่าคำตอบอื่น ๆ ที่ได้รับการโหวตสูงกว่าสำหรับฉัน
สิ่งนี้สามารถทำได้อย่างหรูหราโดยการแทนที่เมธอด sortBy นี่คือตัวอย่าง
var SortedCollection = Backbone.Collection.extend({
initialize: function () {
// Default sort field and direction
this.sortField = "name";
this.sortDirection = "ASC";
},
setSortField: function (field, direction) {
this.sortField = field;
this.sortDirection = direction;
},
comparator: function (m) {
return m.get(this.sortField);
},
// Overriding sortBy (copied from underscore and just swapping left and right for reverse sort)
sortBy: function (iterator, context) {
var obj = this.models,
direction = this.sortDirection;
return _.pluck(_.map(obj, function (value, index, list) {
return {
value: value,
index: index,
criteria: iterator.call(context, value, index, list)
};
}).sort(function (left, right) {
// swap a and b for reverse sort
var a = direction === "ASC" ? left.criteria : right.criteria,
b = direction === "ASC" ? right.criteria : left.criteria;
if (a !== b) {
if (a > b || a === void 0) return 1;
if (a < b || b === void 0) return -1;
}
return left.index < right.index ? -1 : 1;
}), 'value');
}
});
คุณสามารถใช้มันได้ดังนี้:
var collection = new SortedCollection([
{ name: "Ida", age: 26 },
{ name: "Tim", age: 5 },
{ name: "Rob", age: 55 }
]);
//sort by "age" asc
collection.setSortField("age", "ASC");
collection.sort();
//sort by "age" desc
collection.setSortField("age", "DESC");
collection.sort();
โซลูชันนี้ไม่ได้ขึ้นอยู่กับประเภทฟิลด์
// For numbers, dates, and other number-like things
var things = new Backbone.Collection;
things.comparator = function (a, b) { return b - a };
// For strings
things.comparator = function (a, b) {
if (a === b) return 0;
return a < b ? -1 : 1;
};
นี่เป็นวิธีง่ายๆสำหรับผู้ที่ต้องการพลิกคำสั่งซื้อปัจจุบัน จะมีประโยชน์หากคุณมีตารางที่สามารถเรียงลำดับคอลัมน์ได้สองทิศทาง
collection.models = collection.models.reverse()
คุณสามารถรวมเข้ากับสิ่งนี้ได้หากคุณสนใจในตาราง (กาแฟ):
collection.comparator = (model) ->
model.get(sortByType)
collection.sort()
if reverseOrder
collection.models = collection.models.reverse()
สำหรับลำดับย้อนกลับใน id:
comparator: function(object) { return (this.length - object.id) + 1; }
ฉันมีข้อกำหนดที่แตกต่างออกไปเล็กน้อยในการที่ฉันแสดงโมเดลของฉันในตารางและฉันต้องการให้สามารถจัดเรียงตามคอลัมน์ใด ๆ (คุณสมบัติของโมเดล) และจากน้อยไปมากหรือมากไปหาน้อย
ต้องใช้เวลาพอสมควรในการทำให้ทุกกรณีทำงานได้ (โดยที่ค่าอาจเป็นสตริงสตริงว่างวันที่ตัวเลขอย่างไรก็ตามฉันคิดว่านี่ค่อนข้างใกล้เคียง
inverseString: function(str)
{
return str.split("").map(function (letter) { return String.fromCharCode(-(letter.charCodeAt(0))); }).join("");
}
getComparisonValue: function (val, desc)
{
var v = 0;
// Is a string
if (typeof val === "string")
{
// Is an empty string, upgrade to a space to avoid strange ordering
if(val.length === 0)
{
val = " ";
return desc ? this.inverseString(val) : val;
}
// Is a (string) representing a number
v = Number(val);
if (!isNaN(v))
{
return desc ? -1 * v : v;
}
// Is a (string) representing a date
v = Date.parse(val);
if (!isNaN(v))
{
return desc ? -1 * v : v;
}
// Is just a string
return desc ? this.inverseString(val) : val;
}
// Not a string
else
{
return desc ? -1 * val : val;
}
},
ใช้:
comparator: function (item)
{
// Store the collumn to 'sortby' in my global model
var property = app.collections.global.get("sortby");
// Store the direction of the sorting also in the global model
var desc = app.collections.global.get("direction") === "DESC";
// perform a comparison based on property & direction
return this.getComparisonValue(item.get(property), desc);
},
ฉันเพิ่งลบล้างฟังก์ชันการจัดเรียงเพื่อย้อนกลับอาร์เรย์โมเดลเมื่อเสร็จสิ้น นอกจากนี้ฉันยังระงับการทริกเกอร์เหตุการณ์ 'sort' จนกว่าจะเสร็จสิ้นการย้อนกลับ
sort : function(options){
options = options || {};
Backbone.Collection.prototype.sort.call(this, {silent:true});
this.models.reverse();
if (!options.silent){
this.trigger('sort', this, options);
}
return this;
},
พบปัญหานี้เมื่อเร็ว ๆ นี้และเพิ่งตัดสินใจเพิ่มวิธีการ rsort
Collection = Backbone.Collection.extend({
comparator:function(a, b){
return a>b;
},
rsort:function(){
var comparator = this.comparator;
this.comparator = function(){
return -comparator.apply(this, arguments);
}
this.sort();
this.comparator = comparator;
}
});
หวังว่าจะมีคนพบว่าสิ่งนี้มีประโยชน์
นี่เป็นวิธีที่ง่ายและรวดเร็วในการจัดเรียงแบบจำลองของคอลเลคชันโดยใช้ UnderscoreJS
var reverseCollection = _.sortBy(this.models, function(model) {
return self.indexOf(model) * -1;
});