जावास्क्रिप्ट: प्राकृतिक प्रकार के अल्फ़ान्यूमेरिकल स्ट्रिंग्स


173

मैं एक सरणी को क्रमबद्ध करने के लिए सबसे आसान तरीका ढूंढ रहा हूं जिसमें संख्या और पाठ और इनमें से एक संयोजन शामिल है।

उदाहरण के लिए

'123asd'
'19asd'
'12345asd'
'asd123'
'asd12'

में बदल जाता है

'19asd'
'123asd'
'12345asd'
'asd12'
'asd123'

यह मेरे द्वारा पूछे गए एक अन्य प्रश्न के समाधान के साथ संयोजन में उपयोग किया जा रहा है

अपने आप में सॉर्टिंग फ़ंक्शन काम करता है, जो मुझे चाहिए वह एक फ़ंक्शन है जो कह सकता है कि '19asd' '123asd' से छोटा है।

मैं यह जावास्क्रिप्ट में लिख रहा हूँ।

संपादित करें: जैसा कि adormitu ने बताया, मैं जो देख रहा हूं वह प्राकृतिक छंटाई के लिए एक फ़ंक्शन है


stackoverflow.com/questions/51165/…How do you do string comparison in JavaScript? पर भी देखें
Adrien Be

1
मूल प्रश्न 2010 में पूछा गया था, इसलिए यह आश्चर्यजनक नहीं होगा :)
ptrn

जवाबों:


316

अब यह संभव है कि आधुनिक ब्राउज़रों में localeCompare का उपयोग किया जाए। numeric: trueविकल्प पास करके , यह चालाकी से संख्याओं को पहचान लेगा। आप केस-असंवेदनशील का उपयोग कर सकते हैं sensitivity: 'base'। क्रोम, फ़ायरफ़ॉक्स और IE11 में परीक्षण किया गया।

यहाँ एक उदाहरण है। यह रिटर्न 1, मतलब 10 2 के बाद जाता है:

'10'.localeCompare('2', undefined, {numeric: true, sensitivity: 'base'})

प्रदर्शन के लिए जब बड़ी संख्या में तार छांटे जाते हैं, तो लेख कहता है:

बड़ी संख्या में तारों की तुलना करते समय, जैसे कि बड़े सरणियों को छांटना, एक Intl.Collator ऑब्जेक्ट बनाना और उसकी तुलना संपत्ति द्वारा प्रदान किए गए फ़ंक्शन का उपयोग करना बेहतर होता है। डॉक्स लिंक

var collator = new Intl.Collator(undefined, {numeric: true, sensitivity: 'base'});
var myArray = ['1_Document', '11_Document', '2_Document'];
console.log(myArray.sort(collator.compare));


12
यदि आप वस्तुओं की एक सरणी सॉर्ट करना चाहते हैं, तो आप Collator का
TimPietrusky

2
उपरोक्त टिप्पणी को स्पष्ट करने के लिए: "यदि स्थान तर्क प्रदान नहीं किया गया है या अपरिभाषित नहीं है, तो रनटाइम के डिफ़ॉल्ट लोकेल का उपयोग किया जाता है।"
जकी

46

तो आपको एक प्राकृतिक प्रकार की आवश्यकता है ?

यदि हां, तो शायद डेविड कोएले के काम पर आधारित ब्रायन हुइसमैन की यह स्क्रिप्ट आपको चाहिए।

ऐसा लगता है कि ब्रायन हुइसमैन का समाधान अब सीधे डेविड कोएले के ब्लॉग पर होस्ट किया गया है:


सही, प्राकृतिक प्रकार है जो मैं देख रहा हूँ। मैं आपके द्वारा भेजे गए लिंक को
देखूंगा

यह एक बहुत ही अप्राकृतिक प्रकार है। यह एक अल्फ़ाबेटिक प्रकार का उत्पादन नहीं करता है।
tchrist

@tchrist: आपके द्वारा इसका क्या मतलब है "यह एक वर्णानुक्रम प्रकार का उत्पादन नहीं करता है?"
एड्रिन बी

यह ठीक काम करता है लेकिन यह नकारात्मक संख्याओं को सही ढंग से नहीं संभालता है। Ie: यह उत्पादन होगा ['-1'। '-2', '0', '1', '2']।
adrianboimvaser

2
@mhitza इस कोड को एक अच्छा काम करने लगता है github.com/litejs/natural-compare-lite एक त्वरित परीक्षण को देखने के jsbin.com/bevututodavi/1/edit?js,console
एड्रियन रहो

23

मूल्यों की तुलना करने के लिए आप एक तुलना विधि का उपयोग कर सकते हैं-

function naturalSorter(as, bs){
    var a, b, a1, b1, i= 0, n, L,
    rx=/(\.\d+)|(\d+(\.\d+)?)|([^\d.]+)|(\.\D+)|(\.$)/g;
    if(as=== bs) return 0;
    a= as.toLowerCase().match(rx);
    b= bs.toLowerCase().match(rx);
    L= a.length;
    while(i<L){
        if(!b[i]) return 1;
        a1= a[i],
        b1= b[i++];
        if(a1!== b1){
            n= a1-b1;
            if(!isNaN(n)) return n;
            return a1>b1? 1:-1;
        }
    }
    return b[i]? -1:0;
}

लेकिन एक छँटाई में गति के लिए, छँटाई करने से पहले सरणी को रिग करें, इसलिए आपको केवल हर चरण के बजाय केस के रूपांतरण और नियमित अभिव्यक्ति को कम करना होगा।

function naturalSort(ar, index){
    var L= ar.length, i, who, next, 
    isi= typeof index== 'number', 
    rx=  /(\.\d+)|(\d+(\.\d+)?)|([^\d.]+)|(\.(\D+|$))/g;
    function nSort(aa, bb){
        var a= aa[0], b= bb[0], a1, b1, i= 0, n, L= a.length;
        while(i<L){
            if(!b[i]) return 1;
            a1= a[i];
            b1= b[i++];
            if(a1!== b1){
                n= a1-b1;
                if(!isNaN(n)) return n;
                return a1>b1? 1: -1;
            }
        }
        return b[i]!= undefined? -1: 0;
    }
    for(i= 0; i<L; i++){
        who= ar[i];
        next= isi? ar[i][index] || '': who;
        ar[i]= [String(next).toLowerCase().match(rx), who];
    }
    ar.sort(nSort);
    for(i= 0; i<L; i++){
        ar[i]= ar[i][1];
    }
}

यह मेरे मामले में काम करेगा, बाहरी सरणी के आदेश को तय करने वाले आंतरिक सरणी के साथ?
ptrn

क्या है String.prototype.tlc()? क्या यह आपका अपना कोड है या आपको यह कहीं से मिला है? यदि बाद वाला है, तो कृपया पृष्ठ से लिंक करें।
एंडी ई

गलती के लिए खेद है - सही किया, धन्यवाद। यदि आप एक [1] और बी [१] को नियंत्रित करना चाहते हैं, तो एक = स्ट्रिंग ([१]) .LowerCase () का उपयोग करें; b = स्ट्रिंग (b [1])। toLowerCase ();
केनेबेक

मेरे पास केवल डेटा की एक सूची थी जिसे मैं सॉर्ट करना चाहता था, सोचा कि क्रोम देव टूल्स कंसोल में करना आसान होना चाहिए - फ़ंक्शन के लिए धन्यवाद!
अजह 158

9

यदि आपके पास वस्तुओं का एक समूह है, तो आप इस तरह से कर सकते हैं:

myArrayObjects = myArrayObjects.sort(function(a, b) {
  return a.name.localeCompare(b.name, undefined, {
    numeric: true,
    sensitivity: 'base'
  });
});


1
एकदम सही जवाब! धन्यवाद।
हबर्ट 17

5

2019 तक इसे संभालने के लिए सबसे पूरी तरह से चित्रित पुस्तकालय प्राकृतिक-ऑर्डरबी प्रतीत होता है ।

const { orderBy } = require('natural-orderby')

const unordered = [
  '123asd',
  '19asd',
  '12345asd',
  'asd123',
  'asd12'
]

const ordered = orderBy(unordered)

// [ '19asd',
//   '123asd',
//   '12345asd',
//   'asd12',
//   'asd123' ]

यह न केवल तारों के सरणियों को लेता है, बल्कि वस्तुओं की एक सरणी में एक निश्चित कुंजी के मूल्य द्वारा भी सॉर्ट कर सकता है। यह स्वचालित रूप से स्ट्रिंग की पहचान और सॉर्ट कर सकता है: मुद्राएं, तिथियां, मुद्रा और अन्य चीजों का एक गुच्छा।

हैरानी की बात है, यह भी केवल 1.6kB जब gzipped है।


2

एक 8 अंकीय पैडिंग फ़ंक्शन की कल्पना करें जो रूपांतरित करता है:

  • '123asd' -> '00000123asd'
  • '19asd' -> '00000019asd'

हम '19asd' को '123asd' से पहले प्रदर्शित करने में मदद करने के लिए गद्देदार तार का उपयोग कर सकते हैं।

/\d+/gउन सभी नंबरों को खोजने में मदद करने के लिए नियमित अभिव्यक्ति का उपयोग करें जिन्हें गद्देदार करने की आवश्यकता है:

str.replace(/\d+/g, pad)

इस तकनीक का उपयोग करते हुए निम्न प्रदर्शित करता है:

var list = [
    '123asd',
    '19asd',
    '12345asd',
    'asd123',
    'asd12'
];

function pad(n) { return ("00000000" + n).substr(-8); }
function natural_expand(a) { return a.replace(/\d+/g, pad) };
function natural_compare(a, b) {
    return natural_expand(a).localeCompare(natural_expand(b));
}

console.log(list.map(natural_expand).sort()); // intermediate values
console.log(list.sort(natural_compare)); // result

मध्यवर्ती परिणाम दिखाते हैं कि natural_expand () दिनचर्या क्या करती है और आपको यह समझ देती है कि बाद के natural_compare दिनचर्या कैसे काम करेगी:

[
  "00000019asd",
  "00000123asd",
  "00012345asd",
  "asd00000012",
  "asd00000123"
]

आउटपुट:

[
  "19asd",
  "123asd",
  "12345asd",
  "asd12",
  "asd123"
]

1

बिल्डिंग @ एड्रियन पर उत्तर दें ऊपर और ब्रायन हुइसमैन और डेविड कोएले द्वारा बनाए गए कोड का उपयोग करते हुए , यहां वस्तुओं की एक सरणी के लिए संशोधित प्रोटोटाइप सॉर्टिंग है:

//Usage: unsortedArrayOfObjects.alphaNumObjectSort("name");
//Test Case: var unsortedArrayOfObjects = [{name: "a1"}, {name: "a2"}, {name: "a3"}, {name: "a10"}, {name: "a5"}, {name: "a13"}, {name: "a20"}, {name: "a8"}, {name: "8b7uaf5q11"}];
//Sorted: [{name: "8b7uaf5q11"}, {name: "a1"}, {name: "a2"}, {name: "a3"}, {name: "a5"}, {name: "a8"}, {name: "a10"}, {name: "a13"}, {name: "a20"}]

// **Sorts in place**
Array.prototype.alphaNumObjectSort = function(attribute, caseInsensitive) {
  for (var z = 0, t; t = this[z]; z++) {
    this[z].sortArray = new Array();
    var x = 0, y = -1, n = 0, i, j;

    while (i = (j = t[attribute].charAt(x++)).charCodeAt(0)) {
      var m = (i == 46 || (i >=48 && i <= 57));
      if (m !== n) {
        this[z].sortArray[++y] = "";
        n = m;
      }
      this[z].sortArray[y] += j;
    }
  }

  this.sort(function(a, b) {
    for (var x = 0, aa, bb; (aa = a.sortArray[x]) && (bb = b.sortArray[x]); x++) {
      if (caseInsensitive) {
        aa = aa.toLowerCase();
        bb = bb.toLowerCase();
      }
      if (aa !== bb) {
        var c = Number(aa), d = Number(bb);
        if (c == aa && d == bb) {
          return c - d;
        } else {
          return (aa > bb) ? 1 : -1;
        }
      }
    }

    return a.sortArray.length - b.sortArray.length;
  });

  for (var z = 0; z < this.length; z++) {
    // Here we're deleting the unused "sortArray" instead of joining the string parts
    delete this[z]["sortArray"];
  }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.