سؤال

لدي قائمة بالكائنات التي أرغب في فرزها بناءً على الحقل 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"

عندما يتوقع المرء أن يتم "تجميع" الأحرف الخاصة معًا في مكان واحد، باستثناء الحرف الخاص بالمسافة ربما (والذي سيكون دائمًا الحرف الأول).أي إما الكل قبل الأرقام، أو الكل بين الأرقام والحروف (الأحرف الصغيرة والأحرف الكبيرة "معًا" واحدة تلو الأخرى)، أو الكل بعد الحروف.

الاستنتاج الذي توصلت إليه هو أنهم جميعًا فشلوا في تقديم ترتيب ثابت عندما أبدأ في إضافة أحرف غير عادية (على سبيل المثال.أحرف تحتوي على علامات تشكيل أو أحرف مثل الشرطة وعلامة التعجب وما إلى ذلك).

الأبحاث المتعلقة بالتطبيقات المخصصة:

تطبيقات "ترتيب فرز السلسلة الطبيعية" الأصلية للمتصفحات عبر 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 ترتيب فرز مختلف للسلاسل.

البحث عن تطبيقات المتصفح الأصلية:

صعوبة "ترتيب الفرز الطبيعي للسلسلة"

تنفيذ خوارزمية صلبة (بمعنى:متسقة ولكنها تغطي أيضًا مجموعة واسعة من الشخصيات) مهمة صعبة للغاية.يحتوي 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);

قراءة متعمقة:

بفضل إجابة 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)
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top