অ্যান্ডসোর: একাধিক বৈশিষ্ট্যের উপর ভিত্তি করে সাজ্টবাই ()


115

আমি একাধিক বৈশিষ্ট্যের উপর ভিত্তি করে অবজেক্টগুলির সাথে একটি অ্যারের সাজানোর চেষ্টা করছি। উদাহরণস্বরূপ, যদি প্রথম অ্যাট্রিবিউট দুটি অবজেক্টের মধ্যে একই হয় তবে দুটি অ্যাট্রিবিউট দুটি অবজেক্টের কোম্যাপারে ব্যবহার করা উচিত। উদাহরণস্বরূপ, নিম্নলিখিত অ্যারে বিবেচনা করুন:

var patients = [
             [{name: 'John', roomNumber: 1, bedNumber: 1}],
             [{name: 'Lisa', roomNumber: 1, bedNumber: 2}],
             [{name: 'Chris', roomNumber: 2, bedNumber: 1}],
             [{name: 'Omar', roomNumber: 3, bedNumber: 1}]
               ];

এটিকে roomNumberবৈশিষ্ট্য অনুসারে বাছাই করা আমি নিম্নলিখিত কোডটি ব্যবহার করব:

var sortedArray = _.sortBy(patients, function(patient) {
    return patient[0].roomNumber;
});

এটি দুর্দান্ত কাজ করে, তবে কীভাবে আমি এগিয়ে যেতে পারি যাতে 'জন' এবং 'লিসা' সঠিকভাবে বাছাই করা যায়?

উত্তর:


250

sortBy বলে যে এটি একটি স্থিতিশীল বাছাই অ্যালগরিদম তাই আপনার প্রথমে আপনার দ্বিতীয় সম্পত্তি অনুসারে বাছাই করতে সক্ষম হওয়া উচিত, তারপরে আপনার প্রথম সম্পত্তি অনুসারে আবার বাছাই করুন:

var sortedArray = _(patients).chain().sortBy(function(patient) {
    return patient[0].name;
}).sortBy(function(patient) {
    return patient[0].roomNumber;
}).value();

দ্বিতীয়টি যখন sortByজানতে পারে যে জন এবং লিসার একই কক্ষ নম্বর রয়েছে এটি এটি তাদের যেভাবে খুঁজে পেয়েছিল তা ঠিক রাখবে, যা প্রথম sortBy"লিসা, জন" সেট করে।


12
একটি ব্লগ পোস্ট রয়েছে যা এর উপর প্রসারিত হয় এবং আরোহী এবং উত্থাপিত বৈশিষ্ট্যগুলি বাছাই করার বিষয়ে ভাল তথ্য অন্তর্ভুক্ত করে।
অ্যালেক্স সি

4
শৃঙ্খলিত বাছাইয়ের একটি সহজ সমাধান এখানে পাওয়া যাবে । সত্যি কথা বলতে, দেখে মনে হচ্ছে এই উত্তরগুলি দেওয়ার পরে ব্লগ পোস্টটি লেখা হয়েছিল, তবে উপরের উত্তরে কোডটি ব্যবহার করার চেষ্টা করার পরে এবং ব্যর্থ হওয়ার পরে এটি আমাকে এটিকে বের করতে সহায়তা করেছিল।
মাইক দেবেনি

1
আপনি নিশ্চিত রোগী [0]। নাম এবং রোগী [1]। রুম সংখ্যাটি সেখানে সূচক থাকা উচিত? রোগী একটি অ্যারে নয় ...
StinkyCat

[0]Indexer প্রয়োজনীয় কারণ মূল উদাহরণে, তাই patientsবিন্যাসের একটি অ্যারে। এই কারণেই অন্য মন্তব্যে উল্লিখিত ব্লগ পোস্টের "সরল সমাধান" এখানে কাজ করবে না।
ররি ম্যাকলিউড

1
: @ac_fire এখানে যে এখন মৃত লিঙ্ক একটি সংরক্ষণাগার হয় archive.is/tiatQ
lustig

52

এই ক্ষেত্রে আমি মাঝে মাঝে ব্যবহার করি এমন একটি হ্যাকি কৌশল: বৈশিষ্ট্যগুলি এমনভাবে একত্র করুন যাতে ফলাফলটি সাজানো যায়:

var sortedArray = _.sortBy(patients, function(patient) {
  return [patient[0].roomNumber, patient[0].name].join("_");
});

যাইহোক, আমি যেমন বলেছি, এটি বেশ হ্যাকি। এটি সঠিকভাবে করতে আপনি সম্ভবত মূল জাভাস্ক্রিপ্ট sortপদ্ধতিটি ব্যবহার করতে চান :

patients.sort(function(x, y) {
  var roomX = x[0].roomNumber;
  var roomY = y[0].roomNumber;
  if (roomX !== roomY) {
    return compare(roomX, roomY);
  }
  return compare(x[0].name, y[0].name);
});

// General comparison function for convenience
function compare(x, y) {
  if (x === y) {
    return 0;
  }
  return x > y ? 1 : -1;
}

অবশ্যই, এই জায়গায় আপনার অ্যারের বাছাই হবে। যদি আপনি একটি বাছাই করা অনুলিপি চান (যেমন _.sortByআপনাকে দেবে), প্রথমে অ্যারের ক্লোন করুন:

function sortOutOfPlace(sequence, sorter) {
  var copy = _.clone(sequence);
  copy.sort(sorter);
  return copy;
}

একঘেয়েমি থেকে বের হয়ে আমি এর জন্য কেবল একটি সাধারণ সমাধান (যেকোন স্বেচ্ছাসেবীর সংখ্যা অনুসারে বাছাই করতে) লিখেছি: একবার দেখুন


ধন্যবাদ এই সমাধানটির জন্য অনেকটা দ্বিতীয়টি ব্যবহার করে শেষ হয়েছে কারণ আমার বৈশিষ্ট্যগুলি স্ট্রিং এবং সংখ্যা উভয়ই হতে পারে। সুতরাং অ্যারে বাছাই করার কোনও সরল নেটিভ উপায় বলে মনে হচ্ছে না?
খ্রিস্টান আর

3
শুধু return [patient[0].roomNumber, patient[0].name];ছাড়া যথেষ্ট হয় না কেন join?
সিএসবা তোথ

1
আপনার সাধারণ সমাধানের লিঙ্কটি ভেঙে গেছে বলে মনে হচ্ছে (বা সম্ভবত আমি আমাদের প্রক্সি সার্ভারের মাধ্যমে এটি অ্যাক্সেস করতে পারছি না)। আপনি এখানে এটি পোস্ট করতে পারেন?
জেভ স্পিটজ

এছাড়াও, কিভাবে compare- হ্যান্ডেল মান যা আদিম মান নয় undefined, nullঅথবা প্লেইন বস্তু?
জেভ স্পিট্জ

FYI এই হ্যাকটি কেবলমাত্র তখনই কাজ করে যদি আপনি নিশ্চিত হন যে প্রতিটি মানের স্ট্রিং দৈর্ঘ্য অ্যারেতে থাকা সমস্ত আইটেমের জন্য একই।
মাইলেক্স

32

আমি জানি যে আমি পার্টিতে দেরি করেছি, তবে আমি ইতিমধ্যে পরামর্শ দেওয়া ক্লিন-এর এবং দ্রুত-সমাধান সমাধানের জন্য তাদের জন্য এটি যুক্ত করতে চেয়েছিলাম। সর্বাধিক গুরুত্বপূর্ণ সম্পত্তিতে কমপক্ষে গুরুত্বপূর্ণ সম্পত্তির জন্য আপনি সৃস্টবাই কলগুলি চেইন করতে পারেন। নীচের কোডটিতে আমি রোগীদের নামক আসল অ্যারে থেকে রুমনবারের মধ্যে নাম অনুসারে বাছাই করা রোগীদের একটি নতুন অ্যারে তৈরি করি ।

var sortedPatients = _.chain(patients)
  .sortBy('Name')
  .sortBy('RoomNumber')
  .value();

4
আপনি দেরীতে হলেও আপনি এখনও সঠিক: :) ধন্যবাদ!
অ্যালান জিকামু

3
খুব সুন্দর।
জেসন তুরান

11

রোগীদের জন্য আপনার ইনিশিয়ালাইজারটি বিটিডাব্লু কিছুটা অদ্ভুত, তাই না? আপনি কেন এই ভেরিয়েবলটিকে আরম্ভ করবেন না - কারণ এটি সত্যিকারের বস্তুর অ্যারে- আপনি এটি _.ফ্লেটেন () ব্যবহার করে করতে পারবেন এবং একক বস্তুর অ্যারে হিসাবে নয়, এটি টাইপ ইস্যু):

var patients = [
        {name: 'Omar', roomNumber: 3, bedNumber: 1},
        {name: 'John', roomNumber: 1, bedNumber: 1},
        {name: 'Chris', roomNumber: 2, bedNumber: 1},
        {name: 'Lisa', roomNumber: 1, bedNumber: 2},
        {name: 'Kiko', roomNumber: 1, bedNumber: 2}
        ];

আমি তালিকাটি আলাদাভাবে বাছাই করে লিসার বিছানায় কিকো যুক্ত করেছি; শুধু মজাদার জন্য এবং দেখুন কী কী পরিবর্তন করা হবে ...

var sorted = _(patients).sortBy( 
                    function(patient){
                       return [patient.roomNumber, patient.bedNumber, patient.name];
                    });

সাজানো পরিদর্শন করুন এবং আপনি এটি দেখতে পাবেন

[
{bedNumber: 1, name: "John", roomNumber: 1}, 
{bedNumber: 2, name: "Kiko", roomNumber: 1}, 
{bedNumber: 2, name: "Lisa", roomNumber: 1}, 
{bedNumber: 1, name: "Chris", roomNumber: 2}, 
{bedNumber: 1, name: "Omar", roomNumber: 3}
]

সুতরাং আমার উত্তরটি হল: আপনার কলব্যাক ফাংশনে একটি অ্যারে ব্যবহার করুন এটি ড্যান টাওর জবাবের সাথে বেশ মিল , আমি কেবল যোগদানটি ভুলে গেছি (সম্ভবত কারণ আমি অনন্য আইটেমের অ্যারেগুলি সরিয়ে ফেলেছি :))
আপনার ডেটা কাঠামো ব্যবহার করে, তারপর এটি হবে :

var sorted = _(patients).chain()
                        .flatten()
                        .sortBy( function(patient){
                              return [patient.roomNumber, 
                                     patient.bedNumber, 
                                     patient.name];
                        })
                        .value();

এবং একটি টেস্টলোড আকর্ষণীয় হবে ...


সিরিয়াসলি, এটি উত্তর
রাদেক দুচো

7

এই উত্তরগুলির কোনওটিই এক ধরণের একাধিক ক্ষেত্র ব্যবহারের জন্য সাধারণ উদ্দেশ্য পদ্ধতি হিসাবে আদর্শ নয়। উপরের সমস্ত পদ্ধতির অকার্যকর কারণ তাদের হয় হয় একাধিকবার অ্যারে বাছাই করা প্রয়োজন (যা একটি বৃহত পর্যায়ে তালিকার সাহায্যে জিনিসগুলি অনেক ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে বেড়ে যায়) বা ভিএম পরিষ্কার করার জন্য তারা প্রচুর পরিমাণে আবর্জনা তৈরি করতে পারে (এবং শেষ পর্যন্ত ধীর গতিতে হবে) প্রোগ্রাম ডাউন)।

এখানে একটি সমাধান পাওয়া যাবে যে দ্রুত, কার্যকর, সহজে বিপরীত বাছাই অনুমতি দেয়, এবং ব্যবহার করা যেতে পারে underscoreবা lodash, বা সাথে সরাসরিArray.sort

সর্বাধিক গুরুত্বপূর্ণ অংশটি হল compositeComparatorপদ্ধতি, যা তুলনামূলক ফাংশনগুলির একটি অ্যারে নেয় এবং একটি নতুন সংমিশ্রণ তুলনামূলক ফাংশন প্রদান করে।

/**
 * Chains a comparator function to another comparator
 * and returns the result of the first comparator, unless
 * the first comparator returns 0, in which case the
 * result of the second comparator is used.
 */
function makeChainedComparator(first, next) {
  return function(a, b) {
    var result = first(a, b);
    if (result !== 0) return result;
    return next(a, b);
  }
}

/**
 * Given an array of comparators, returns a new comparator with
 * descending priority such that
 * the next comparator will only be used if the precending on returned
 * 0 (ie, found the two objects to be equal)
 *
 * Allows multiple sorts to be used simply. For example,
 * sort by column a, then sort by column b, then sort by column c
 */
function compositeComparator(comparators) {
  return comparators.reduceRight(function(memo, comparator) {
    return makeChainedComparator(comparator, memo);
  });
}

আপনি যে ক্ষেত্রগুলি বাছাই করতে চান তার তুলনা করার জন্য আপনার একটি তুলনামূলক ফাংশনও প্রয়োজন। naturalSortফাংশন একটি নির্দিষ্ট ক্ষেত্র দেয়া comparator তৈরি করবে। বিপরীত বাছাইয়ের জন্য একটি তুলনামূলক লেখা খুব নগণ্য।

function naturalSort(field) {
  return function(a, b) {
    var c1 = a[field];
    var c2 = b[field];
    if (c1 > c2) return 1;
    if (c1 < c2) return -1;
    return 0;
  }
}

(এখন পর্যন্ত সমস্ত কোড পুনরায় ব্যবহারযোগ্য এবং ইউটিলিটি মডিউলে রাখা যেতে পারে, উদাহরণস্বরূপ)

এর পরে, আপনাকে সম্মিলিত তুলনামূলক তৈরি করতে হবে। আমাদের উদাহরণস্বরূপ, এটি দেখতে এরকম হবে:

var cmp = compositeComparator([naturalSort('roomNumber'), naturalSort('name')]);

এটি নামের পরে কক্ষের নম্বর অনুসারে বাছাই করবে। অতিরিক্ত সাজানোর মানদণ্ড যুক্ত করা তুচ্ছ এবং এটি বাছাইয়ের কার্যকারিতাগুলিকে প্রভাবিত করে না।

var patients = [
 {name: 'John', roomNumber: 3, bedNumber: 1},
 {name: 'Omar', roomNumber: 2, bedNumber: 1},
 {name: 'Lisa', roomNumber: 2, bedNumber: 2},
 {name: 'Chris', roomNumber: 1, bedNumber: 1},
];

// Sort using the composite
patients.sort(cmp);

console.log(patients);

নিম্নলিখিত প্রদান করে

[ { name: 'Chris', roomNumber: 1, bedNumber: 1 },
  { name: 'Lisa', roomNumber: 2, bedNumber: 2 },
  { name: 'Omar', roomNumber: 2, bedNumber: 1 },
  { name: 'John', roomNumber: 3, bedNumber: 1 } ]

যে কারণে আমি এই পদ্ধতির পছন্দ করি তা হ'ল এটি একটি স্বেচ্ছাসেবী ক্ষেত্রগুলিতে দ্রুত বাছাইয়ের অনুমতি দেয়, প্রচুর আবর্জনা তৈরি করে না বা সাজানোর ভিতরে স্ট্রিং কনটেনটেশন সম্পাদন করে না এবং সহজেই ব্যবহার করা যায় যাতে কিছু কলামগুলি বিপরীত অনুসারে বাছাই করা হয় যখন অর্ডার কলামগুলি প্রাকৃতিকভাবে ব্যবহার করে সাজান.



2

সম্ভবত এই উত্তরগুলি যখন লেখা হয়েছিল তার চেয়ে এখন আন্ডারস্কোর.জেএস বা জাভাস্ক্রিপ্ট ইঞ্জিনগুলি এখন অন্যরকম, তবে আমি কেবল সাজানোর কীগুলির একটি অ্যারের ফিরিয়ে এটিকে সমাধান করতে সক্ষম হয়েছি।

var input = [];

for (var i = 0; i < 20; ++i) {
  input.push({
    a: Math.round(100 * Math.random()),
    b: Math.round(3 * Math.random())
  })
}

var output = _.sortBy(input, function(o) {
  return [o.b, o.a];
});

// output is now sorted by b ascending, a ascending

ক্রিয়াকলাপে, দয়া করে এই ঝাঁকুনি দেখুন: https://jsfiddle.net/mikeular/xenu3u91/


2

আপনি যে বৈশিষ্ট্যের সাথে বাছাই করতে চান তার কেবলমাত্র একটি অ্যারেটি ফিরিয়ে দিন :

ES6 সিনট্যাক্স

var sortedArray = _.sortBy(patients, patient => [patient[0].name, patient[1].roomNumber])

ইএস 5 সিনট্যাক্স

var sortedArray = _.sortBy(patients, function(patient) { 
    return [patient[0].name, patient[1].roomNumber]
})

কোনও সংখ্যাকে স্ট্রিতে রূপান্তর করার কোনও পার্শ্ব প্রতিক্রিয়া নেই।


1

আপনি যে বৈশিষ্ট্যগুলি পুনরুক্তি করে বাছাই করতে চান তাতে আপনি একত্রিত করতে পারেন:

return [patient[0].roomNumber,patient[0].name].join('|');

বা সমতুল্য কিছু।

দ্রষ্টব্য: যেহেতু আপনি সংখ্যাসূচক কক্ষ সংখ্যাটি একটি স্ট্রিংয়ে রূপান্তর করছেন, আপনার রুম নম্বর> 10 থাকলে আপনার কিছু করতে হবে অন্যথায় 11 আগে 2 আসবে 2 আপনি সমস্যা সমাধানের জন্য নেতৃস্থানীয় শূন্যগুলি দিয়ে প্যাড করতে পারেন, পরিবর্তে 01 এর পরিবর্তে 1।


1

আমি মনে করি আপনি এর _.orderByপরিবর্তে আরও ভাল ব্যবহার করতে চান sortBy:

_.orderBy(patients, ['name', 'roomNumber'], ['asc', 'desc'])

4
আপনি কি নিশ্চিত যে অর্ডারবাই আন্ডারস্কোরে রয়েছে? আমি এটি ডক্স বা আমার .d.ts ফাইলে দেখতে পাচ্ছি না।
জাকারি দাও

1
আন্ডারস্কোরে অর্ডারবাই নেই।
আফ্রোমোগলি

1
_.orderByকাজ করে, তবে এটি লড্যাশ লাইব্রেরির একটি পদ্ধতি, আন্ডারস্কোর নয়: লড্যাশ ডকস / ডকস / ৪.১order.৪ # অর্ডার বাই লড্যাশ আন্ডারস্কোরের জন্য বেশিরভাগই একটি ড্রপ-ইন প্রতিস্থাপন, সুতরাং এটি ওপি'র পক্ষে উপযুক্ত হতে পারে।
মাইকে কে

0

আপনি যদি কৌনিক ব্যবহার করছেন বলে মনে হয় তবে আপনি কোনও জেএস বা সিএসএস হ্যান্ডলার যুক্ত করার পরিবর্তে এইচটিএমএল ফাইলটিতে এর নম্বর ফিল্টারটি ব্যবহার করতে পারেন। উদাহরণ স্বরূপ:

  No fractions: <span>{{val | number:0}}</span><br>

এই উদাহরণে, যদি মান = 1234567, এটি হিসাবে প্রদর্শিত হবে

  No fractions: 1,234,567

উদাহরণ এবং আরও নির্দেশিকা এখানে: https://docs.angularjs.org/api/ng/filter/number

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.