كيفية فرز السلاسل في جافا سكريبت
-
09-06-2019 - |
سؤال
لدي قائمة بالكائنات التي أرغب في فرزها بناءً على الحقل attr
من نوع السلسلة.حاولت استخدام -
list.sort(function (a, b) {
return a.attr - b.attr
})
ولكن وجدت ذلك -
لا يبدو أنه يعمل مع السلاسل في JavaScript.كيف يمكنني فرز قائمة الكائنات بناءً على سمة بسلسلة من النوع؟
المحلول
يستخدم String.prototype.localeCompare
على سبيل المثال الخاص بك:
list.sort(function (a, b) {
return ('' + a.attr).localeCompare(b.attr);
})
نحن نجبر a.attr على أن يكون سلسلة لتجنب الاستثناءات. localeCompare
تم دعمه منذ إنترنت إكسبلورر 6 وفايرفوكس 1.قد ترى أيضًا الكود التالي مستخدمًا ولا يحترم اللغة:
if (item1.attr < item2.attr)
return -1;
if ( item1.attr > item2.attr)
return 1;
return 0;
نصائح أخرى
إجابة محدثة (أكتوبر 2014)
لقد كنت منزعجًا حقًا بشأن ترتيب الفرز الطبيعي للسلسلة، لذا استغرقت بعض الوقت للتحقيق في هذه المشكلة.آمل أن يساعد هذا.
قصة طويلة قصيرة
localeCompare()
دعم الشخصيات أمر سيء، فقط استخدمه.كما أشار Shog9
, ، الجواب على سؤالك هو:
return item1.attr.localeCompare(item2.attr);
تم العثور على أخطاء في جميع تطبيقات "ترتيب فرز السلسلة الطبيعية" المخصصة لجافا سكريبت
هناك مجموعة لا بأس بها من التطبيقات المخصصة، التي تحاول إجراء مقارنة سلسلة بشكل أكثر دقة تسمى "ترتيب فرز السلسلة الطبيعي"
عند "اللعب" بهذه التطبيقات، كنت ألاحظ دائمًا بعض الاختيارات الغريبة "لترتيب الفرز الطبيعي"، أو بالأحرى الأخطاء (أو الإغفالات في أفضل الحالات).
عادةً، لا تتم معالجة الأحرف الخاصة (مسافة، شرطة، علامة الضم، الأقواس، وما إلى ذلك) بشكل صحيح.
ستجدهم بعد ذلك يظهرون مختلطين في أماكن مختلفة، وعادة ما يكون ذلك:
- بعضها سيكون بين الحرف الكبير "Z" والحرف الصغير "a"
- سيكون بعضها بين "9" والحرف الكبير "A"
- بعضها سيكون بعد الحرف الصغير "z"
عندما يتوقع المرء أن يتم "تجميع" الأحرف الخاصة معًا في مكان واحد، باستثناء الحرف الخاص بالمسافة ربما (والذي سيكون دائمًا الحرف الأول).أي إما الكل قبل الأرقام، أو الكل بين الأرقام والحروف (الأحرف الصغيرة والأحرف الكبيرة "معًا" واحدة تلو الأخرى)، أو الكل بعد الحروف.
الاستنتاج الذي توصلت إليه هو أنهم جميعًا فشلوا في تقديم ترتيب ثابت عندما أبدأ في إضافة أحرف غير عادية (على سبيل المثال.أحرف تحتوي على علامات تشكيل أو أحرف مثل الشرطة وعلامة التعجب وما إلى ذلك).
الأبحاث المتعلقة بالتطبيقات المخصصة:
Natural Compare Lite
https://github.com/litejs/natural-compare-lite :فشل في الفرز بشكل متسق https://github.com/litejs/natural-compare-lite/issues/1 و http://jsbin.com/bevututodavi/1/edit?js,console فرز الأحرف اللاتينية الأساسية http://jsbin.com/bevututodavi/5/edit?js,consoleNatural Sort
https://github.com/javve/natural-sort :فشل في الفرز بشكل متسق، راجع المشكلة https://github.com/javve/natural-sort/issues/7 وانظر فرز الأحرف اللاتينية الأساسية http://jsbin.com/cipimosedoqe/3/edit?js,consoleJavascript Natural Sort
https://github.com/overset/javascript-natural-sort :يبدو مهملاً إلى حد ما منذ فبراير 2012، فشل في الفرز بشكل متسق، راجع المشكلة https://github.com/overset/javascript-natural-sort/issues/16Alphanum
http://www.davekoelle.com/files/alphanum.js ، فشل في الفرز بشكل متسق، انظر http://jsbin.com/tuminoxifuyo/1/edit?js,console
تطبيقات "ترتيب فرز السلسلة الطبيعية" الأصلية للمتصفحات عبر localeCompare()
localeCompare()
يتم دعم التنفيذ الأقدم (بدون وسيطات الإعدادات المحلية والخيارات) بواسطة IE6+، راجع http://msdn.microsoft.com/en-us/library/ie/s4esdbwz(v=vs.94).aspx (قم بالتمرير لأسفل إلى طريقة localeCompare()).المدمج في localeCompare()
تقوم الطريقة بعمل أفضل بكثير في الفرز، حتى الأحرف الدولية والخاصة.المشكلة الوحيدة باستخدام localeCompare()
الطريقة هي ذلك "الإعدادات المحلية وترتيب الفرز المستخدم يعتمدان بشكل كامل على التنفيذ".بمعنى آخر، عند استخدام localeCompare مثل stringOne.localeCompare(stringTwo):لدى Firefox وSafari وChrome وIE ترتيب فرز مختلف للسلاسل.
البحث عن تطبيقات المتصفح الأصلية:
- http://jsbin.com/beboroyifomu/1/edit?js,console - مقارنة الأحرف اللاتينية الأساسية مع localeCompare()http://jsbin.com/viyucavudela/2/ - مقارنة الأحرف اللاتينية الأساسية مع localeCompare() للاختبار على IE8
- http://jsbin.com/beboroyifomu/2/edit?js,console - الأحرف اللاتينية الأساسية في مقارنة السلسلة:التحقق من الاتساق في السلسلة مقابل عندما يكون الحرف بمفرده
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare - يدعم IE11+ وسائط اللغات والخيارات الجديدة
صعوبة "ترتيب الفرز الطبيعي للسلسلة"
تنفيذ خوارزمية صلبة (بمعنى:متسقة ولكنها تغطي أيضًا مجموعة واسعة من الشخصيات) مهمة صعبة للغاية.يحتوي UTF8 أكثر من 2000 حرف & يغطي أكثر من 120 مخطوطة (لغات).وأخيرا، هناك بعض المواصفات لهذه المهام، تسمى "خوارزمية ترتيب Unicode"، والتي يمكن العثور عليها في http://www.unicode.org/reports/tr10/ .يمكنك العثور على مزيد من المعلومات حول هذا الأمر في هذا السؤال الذي نشرته https://softwareengineering.stackexchange.com/questions/257286/is-there-any-language-agnostic-specation-for-string-natural-sorting-order
الاستنتاج النهائي
لذا، بالنظر إلى المستوى الحالي من الدعم الذي توفره تطبيقات جافا سكريبت المخصصة التي صادفتها، فمن المحتمل ألا نرى أي شيء يقترب من دعم كل هذه الأحرف والنصوص (اللغات).ومن ثم أفضل استخدام طريقة localeCompare() الأصلية للمتصفحات.نعم، لديها الجانب السلبي المتمثل في كونها غير متسقة عبر المتصفحات ولكن الاختبارات الأساسية تظهر أنها تغطي نطاقًا أوسع بكثير من الأحرف، مما يسمح بترتيبات فرز قوية وذات معنى.
لذا كما أشار Shog9
, ، الجواب على سؤالك هو:
return item1.attr.localeCompare(item2.attr);
قراءة متعمقة:
- https://softwareengineering.stackexchange.com/questions/257286/is-there-any-language-agnostic-specation-for-string-natural-sorting-order
- كيف يمكنك إجراء مقارنة السلسلة في JavaScript؟
- جافا سكريبت :النوع الطبيعي من السلاسل الأبجدية الرقمية
- فرز مصفوفة من العناصر الرقمية والأبجدية (الفرز الطبيعي)
- فرز مجموعة ألفا / رقمية مختلطة
- https://web.archive.org/web/20130929122019/http://my.opera.com/GreyWyvern/blog/show.dml/1671288
- https://web.archive.org/web/20131005224909/http://www.davekoelle.com/alphanum.html
- http://snipplr.com/view/36012/javascript-natural-sort/
- http://blog.codinghorror.com/sorting-for-humans-natural-sort-order/
بفضل إجابة Shog9 اللطيفة، والتي وضعتني في الاتجاه "الصحيح" الذي أعتقده
الإجابة (في ECMAScript الحديثة)
list.sort((a, b) => (a.attr > b.attr) - (a.attr < b.attr))
أو
list.sort((a, b) => +(a.attr > b.attr) || -(a.attr < b.attr))
وصف
يؤدي إرسال قيمة منطقية إلى رقم إلى ما يلي:
true
->1
false
->0
فكر في ثلاثة أنماط محتملة:
- x أكبر من y:
(x > y) - (y < x)
->1 - 0
->1
- س يساوي ص:
(x > y) - (y < x)
->0 - 0
->0
- x أصغر من y:
(x > y) - (y < x)
->0 - 1
->-1
(بديل)
- x أكبر من y:
+(x > y) || -(x < y)
->1 || 0
->1
- س يساوي ص:
+(x > y) || -(x < y)
->0 || 0
->0
- x أصغر من y:
+(x > y) || -(x < y)
->0 || -1
->-1
لذا فإن هذه المنطق تعادل وظائف مقارنة الفرز النموذجية.
if (x == y) {
return 0;
}
return x > y ? 1 : -1;
يجب عليك استخدام > أو < و == هنا.لذلك سيكون الحل:
list.sort(function(item1, item2) {
var val1 = item1.attr,
val2 = item2.attr;
if (val1 == val2) return 0;
if (val1 > val2) return 1;
if (val1 < val2) return -1;
});
لقد كنت منزعجًا من هذا الأمر لفترة طويلة، لذلك قمت أخيرًا بالبحث في هذا الأمر وأعطيتك هذا السبب الطويل الأمد لسبب كون الأمور على ما هي عليه.
من المواصفات:
Section 11.9.4 The Strict Equals Operator ( === )
The production EqualityExpression : EqualityExpression === RelationalExpression
is evaluated as follows:
- Let lref be the result of evaluating EqualityExpression.
- Let lval be GetValue(lref).
- Let rref be the result of evaluating RelationalExpression.
- Let rval be GetValue(rref).
- Return the result of performing the strict equality comparison
rval === lval. (See 11.9.6)
والآن ننتقل إلى 11.9.6
11.9.6 The Strict Equality Comparison Algorithm
The comparison x === y, where x and y are values, produces true or false.
Such a comparison is performed as follows:
- If Type(x) is different from Type(y), return false.
- If Type(x) is Undefined, return true.
- If Type(x) is Null, return true.
- If Type(x) is Number, then
...
- If Type(x) is String, then return true if x and y are exactly the
same sequence of characters (same length and same characters in
corresponding positions); otherwise, return false.
هذا كل شيء. يُرجع عامل المساواة الثلاثية المطبق على السلاسل صحيحًا إذا كانت الوسيطات هي نفس السلاسل تمامًا (نفس الطول ونفس الأحرف في المواضع المقابلة).
لذا ===
سيعمل في الحالات التي نحاول فيها مقارنة السلاسل التي قد تكون وصلت من مصادر مختلفة، ولكننا نعلم أنها ستحتوي في النهاية على نفس القيم - وهو سيناريو شائع بدرجة كافية للسلاسل المضمنة في التعليمات البرمجية الخاصة بنا.على سبيل المثال، إذا كان لدينا متغير اسمه connection_state
, ، ونرغب في معرفة أي من الحالات التالية ['connecting', 'connected', 'disconnecting', 'disconnected']
هل هو موجود الآن، يمكننا استخدام مباشرة ===
.
ولكن هناك المزيد.فوق 11.9.4 مباشرة، هناك ملاحظة قصيرة:
NOTE 4
Comparison of Strings uses a simple equality test on sequences of code
unit values. There is no attempt to use the more complex, semantically oriented
definitions of character or string equality and collating order defined in the
Unicode specification. Therefore Strings values that are canonically equal
according to the Unicode standard could test as unequal. In effect this
algorithm assumes that both Strings are already in normalized form.
همم.ماذا الان؟يمكن أن تكون السلاسل التي تم الحصول عليها خارجيًا، وعلى الأرجح ستكون، غريبة ولطيفة ===
لن توفيهم العدالةيأتي localeCompare
إلى الإنقاذ:
15.5.4.9 String.prototype.localeCompare (that)
...
The actual return values are implementation-defined to permit implementers
to encode additional information in the value, but the function is required
to define a total ordering on all Strings and to return 0 when comparing
Strings that are considered canonically equivalent by the Unicode standard.
يمكننا العودة إلى المنزل الآن.
ليرة تركية؛دكتور؛
لمقارنة السلاسل في جافا سكريبت، استخدم localeCompare
;إذا كنت تعلم أن السلاسل لا تحتوي على مكونات غير ASCII لأنها، على سبيل المثال، ثوابت برنامج داخلية، إذن ===
يعمل أيضا.
وظيفة السهم الثلاثي المتداخلة
(a,b) => (a < b ? -1 : a > b ? 1 : 0)
في العملية التي أجريتها في سؤالك الأولي، تقوم بالعملية التالية:
item1.attr - item2.attr
لذلك، على افتراض أن هذه أرقام (أي.item1.attr = "1"، item2.attr = "2") لا يزال بإمكانك استخدام عامل التشغيل "===" (أو غيره من المقيمين الصارمين) بشرط التأكد من النوع.يجب أن يعمل ما يلي:
return parseInt(item1.attr) - parseInt(item2.attr);
إذا كانت أبجدية رقمية، فاستخدم localCompare().
list.sort(function(item1, item2){
return +(item1.attr > item2.attr) || +(item1.attr === item2.attr) - 1;
})
كيفية عمل العينات:
+('aaa'>'bbb')||+('aaa'==='bbb')-1
+(false)||+(false)-1
0||0-1
-1
+('bbb'>'aaa')||+('bbb'==='aaa')-1
+(true)||+(false)-1
1||0-1
1
+('aaa'>'aaa')||+('aaa'==='aaa')-1
+(false)||+(true)-1
0||1-1
0
<!doctype html>
<html>
<body>
<p id = "myString">zyxtspqnmdba</p>
<p id = "orderedString"></p>
<script>
var myString = document.getElementById("myString").innerHTML;
orderString(myString);
function orderString(str) {
var i = 0;
var myArray = str.split("");
while (i < str.length){
var j = i + 1;
while (j < str.length) {
if (myArray[j] < myArray[i]){
var temp = myArray[i];
myArray[i] = myArray[j];
myArray[j] = temp;
}
j++;
}
i++;
}
var newString = myArray.join("");
document.getElementById("orderedString").innerHTML = newString;
}
</script>
</body>
</html>
var str = ['v','a','da','c','k','l']
var b = str.join('').split('').sort().reverse().join('')
console.log(b)