जावास्क्रिप्ट में कई सरणियों का कार्टेशियन उत्पाद


112

आप जावास्क्रिप्ट में कई सरणियों के कार्टेशियन उत्पाद को कैसे लागू करेंगे?

उदहारण के लिए,

cartesian([1, 2], [10, 20], [100, 200, 300]) 

लौट जाना चाहिए

[
  [1, 10, 100],
  [1, 10, 200],
  [1, 10, 300],
  [2, 10, 100],
  [2, 10, 200]
  ...
]


3
इसे js-combinatorics मॉड्यूल में लागू किया गया: github.com/dankogai/js-combinatorics
Erel Segal-Halevi


मैं अंडरस्कोर के बारे में सहमत हूं। जेएस, लेकिन मुझे यकीन नहीं है कि मैं देख रहा हूं कि फंक्शनल-प्रोग्रामिंग टैग को हटाने से @le_m कैसे मदद करेगा
viebel

Fwiw, d3 d3.cross(a, b[, reducer])फरवरी में जोड़ा गया। github.com/d3/d3-array#cross
Toph

जवाबों:


105

2017 अपडेट: वेनिला जेएस के साथ 2-लाइन उत्तर

यहां सभी उत्तर अत्यधिक जटिल हैं , उनमें से अधिकांश कोड की 20 लाइनें या उससे भी अधिक लेते हैं।

यह उदाहरण वनिला जावास्क्रिप्ट की सिर्फ दो पंक्तियों का उपयोग करता है , कोई लॉश, अंडरस्कोर या अन्य लाइब्रेरी नहीं:

let f = (a, b) => [].concat(...a.map(a => b.map(b => [].concat(a, b))));
let cartesian = (a, b, ...c) => b ? cartesian(f(a, b), ...c) : a;

अपडेट करें:

यह ऊपर के समान है, लेकिन एयरबिन जावास्क्रिप्ट स्टाइल गाइड का सख्ती से पालन करने के लिए सुधार हुआ है - जिसका उपयोग करके मान्य किया गया है ESLint साथ eslint-config-Airbnb आधार :

const f = (a, b) => [].concat(...a.map(d => b.map(e => [].concat(d, e))));
const cartesian = (a, b, ...c) => (b ? cartesian(f(a, b), ...c) : a);

मूल कोड के साथ लिंटर समस्याओं के बारे में बताने के लिए ZuBB के लिए विशेष धन्यवाद ।

उदाहरण

यह आपके प्रश्न का सटीक उदाहरण है:

let output = cartesian([1,2],[10,20],[100,200,300]);

उत्पादन

यह उस कमांड का आउटपुट है:

[ [ 1, 10, 100 ],
  [ 1, 10, 200 ],
  [ 1, 10, 300 ],
  [ 1, 20, 100 ],
  [ 1, 20, 200 ],
  [ 1, 20, 300 ],
  [ 2, 10, 100 ],
  [ 2, 10, 200 ],
  [ 2, 10, 300 ],
  [ 2, 20, 100 ],
  [ 2, 20, 200 ],
  [ 2, 20, 300 ] ]

डेमो

डेमो देखें:

वाक्य - विन्यास

मैंने यहां जो वाक्य-विन्यास का उपयोग किया है, वह कोई नई बात नहीं है। मेरा उदाहरण प्रसार ऑपरेटर और बाकी मापदंडों का उपयोग करता है - जून 2015 को प्रकाशित ईसीएमए -262 मानक के 6 वें संस्करण में परिभाषित जावास्क्रिप्ट की विशेषताएं और बहुत पहले विकसित, जिसे ईएस 6 या ईएस2015 के रूप में जाना जाता है। देख:

यह इस तरह से कोड को इतना सरल बनाता है कि इसका उपयोग न करना एक पाप है। पुराने प्लेटफ़ॉर्म के लिए जो इसे मूल रूप से समर्थन नहीं करते हैं, आप इसे पुराने सिंटैक्स में ट्रांसपाइल करने के लिए हमेशा बैबेल या अन्य टूल का उपयोग कर सकते हैं - और वास्तव में बैबेल द्वारा ट्रांसलेट किया गया मेरा उदाहरण अभी भी यहां के अधिकांश उदाहरणों की तुलना में छोटा और सरल है, लेकिन यह नहीं है वास्तव में मामला क्योंकि ट्रांसप्लीकेशन का आउटपुट कुछ ऐसा नहीं है जिसे आपको समझने या बनाए रखने की आवश्यकता है, यह सिर्फ एक तथ्य है जो मुझे दिलचस्प लगा।

निष्कर्ष

कोड की सौ पंक्तियों को लिखने की आवश्यकता नहीं है जो बनाए रखना कठिन है और इस तरह की एक साधारण चीज के लिए संपूर्ण पुस्तकालयों का उपयोग करने की आवश्यकता नहीं है, जब वेनिला जावास्क्रिप्ट की दो पंक्तियों को आसानी से काम मिल सकता है। जैसा कि आप देख सकते हैं कि यह भाषा की आधुनिक विशेषताओं का उपयोग करने के लिए वास्तव में भुगतान करता है और ऐसे मामलों में जहां आपको आधुनिक सुविधाओं के मूल समर्थन के साथ पुरातन प्लेटफार्मों का समर्थन करने की आवश्यकता नहीं है, आप हमेशा नए वाक्यविन्यास को पुराने के लिए ट्रांसफ़िल करने के लिए बैबल या अन्य टूल का उपयोग कर सकते हैं ।

यह 1995 की तरह कोड नहीं है

जावास्क्रिप्ट विकसित होता है और यह एक कारण के लिए ऐसा करता है। TC39 नई सुविधाओं को जोड़ने के साथ भाषा डिजाइन का एक अद्भुत काम करता है और ब्राउज़र विक्रेता उन सुविधाओं को लागू करने का एक अद्भुत काम करते हैं।

ब्राउज़रों में किसी भी सुविधा के मूल समर्थन की वर्तमान स्थिति देखने के लिए, देखें:

नोड संस्करणों में समर्थन देखने के लिए, देखें:

उन प्लेटफार्मों पर आधुनिक सिंटैक्स का उपयोग करने के लिए जो इसे मूल रूप से समर्थन नहीं करते हैं, Babel का उपयोग करें:


यहां टाइप टाइप करने के लिए मामूली परिवर्तन के साथ एक टाइपस्क्रिप्ट संस्करण है, जिस प्रकार से टाइप करना सरणी को फैलाना है। gist.github.com/ssippe/1f92625532eef28be697474f898efb23ef
सैम सिप्प

1
@ आरएसपी वास्तव में अच्छे उत्तर के लिए बहुत बहुत धन्यवाद। हालाँकि, मैं आपको छायांकित चर की चेतावनी प्राप्त करने के लिए इसे थोड़ा सुधारने के लिए कहना चाहूंगा (2 स्थानीय ab
संस्करण

7
"1995 की तरह कोड न करें" - अप्रिय होने की आवश्यकता नहीं है, हर किसी ने अभी तक नहीं पकड़ा है।
गॉडवॉकर

7
हालांकि यह ठीक है जब साथ खिलाया विफल रहता है ['a', 'b'], [1,2], [[9], [10]]जो निकलेगा [ [ 'a', 1, 9 ], [ 'a', 1, 10 ], [ 'a', 2, 9 ], [ 'a', 2, 10 ], [ 'b', 1, 9 ], [ 'b', 1, 10 ], [ 'b', 2, 9 ], [ 'b', 2, 10 ] ]परिणाम के रूप में। मेरा मतलब है कि आइटम के प्रकार को नहीं रखेंगे [[9], [10]]
रेडू

1
चूंकि हम ...पहले से ही उपयोग कर रहे हैं , [].concat(...[array])बस नहीं बनना चाहिए[...array] ?
लजार लुजुबेनोविक

88

यहां समस्या का एक कार्यात्मक समाधान है (बिना किसी परिवर्तनशील परिवर्तन के !) का उपयोग करके reduceऔर flatten, द्वारा प्रदान किया गया underscore.js:

function cartesianProductOf() {
    return _.reduce(arguments, function(a, b) {
        return _.flatten(_.map(a, function(x) {
            return _.map(b, function(y) {
                return x.concat([y]);
            });
        }), true);
    }, [ [] ]);
}

// [[1,3,"a"],[1,3,"b"],[1,4,"a"],[1,4,"b"],[2,3,"a"],[2,3,"b"],[2,4,"a"],[2,4,"b"]]
console.log(cartesianProductOf([1, 2], [3, 4], ['a']));  
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.9.1/underscore.js"></script>

टिप्पणी: यह समाधान http://cwestblog.com/2011/05/02/cartesian-product-of-multiple-arrays/ से प्रेरित था


इस उत्तर में एक टाइपो है, एक "सच नहीं होना चाहिए" (हो सकता है कि आपने इस पोस्ट को बनाने के बाद से लॉश बदल दिया हो?)
क्रिस जेफरसन

@ChrisJefferson दूसरा परम flattenहै चपटे उथले बनाने के लिए। यह यहाँ अनिवार्य है!
विबेल

4
क्षमा करें, यह एक लॉश / अंडरस्कोर असंगति है, उन्होंने ध्वज के चारों ओर स्वैप किया।
क्रिस जेफरसन

1
तो जब सपाट, उपयोग trueके साथ अंडरस्कोर और उपयोग falseके साथ lodash उथले सपाट सुनिश्चित करने के लिए।
अक्सेली पाल्ने

इस फ़ंक्शन को कैसे संशोधित करें ताकि यह सरणियों को स्वीकार करे?

44

यहाँ किसी भी पुस्तकालय का उपयोग किए बिना, सादे जावास्क्रिप्ट में @ viebel के कोड का संशोधित संस्करण दिया गया है:

function cartesianProduct(arr) {
    return arr.reduce(function(a,b){
        return a.map(function(x){
            return b.map(function(y){
                return x.concat([y]);
            })
        }).reduce(function(a,b){ return a.concat(b) },[])
    }, [[]])
}

var a = cartesianProduct([[1, 2,3], [4, 5,6], [7, 8], [9,10]]);
console.log(JSON.stringify(a));


2
कार्टेशियनप्रोडक्ट ([[१]], [२], [३]], ['ए ’, [बी’], [[ma गामा ’], [[' अल्फा’]], [ii ज़ी ’] के लिए विफल 'faa']]) जैसा कि यह ['गामा'] को 'गामा' और [['अल्फ़ा']] को ['अल्फ़ा']
Mnn

क्योंकि .concat(y)इसके बजाय.concat([ y ])
धन्यवाद

@ थैंक्यू आप टिप्पणी के बजाय सीधे उत्तर को संपादित कर सकते हैं, बस क्या अब इसकी कोई आवश्यकता नहीं है: पी
ओलिवियर लालोंडे

28

ऐसा लगता है कि समुदाय को लगता है कि यह एक संदर्भ कार्यान्वयन को खोजने के लिए तुच्छ और या आसान है, संक्षिप्त निरीक्षण पर मैं ऐसा नहीं कर सकता या शायद यह है कि मुझे पहिया का फिर से आविष्कार करना या कक्षा की तरह प्रोग्रामिंग समस्याओं को हल करना पसंद है या तो अपने भाग्यशाली दिन। :

function cartProd(paramArray) {

  function addTo(curr, args) {

    var i, copy, 
        rest = args.slice(1),
        last = !rest.length,
        result = [];

    for (i = 0; i < args[0].length; i++) {

      copy = curr.slice();
      copy.push(args[0][i]);

      if (last) {
        result.push(copy);

      } else {
        result = result.concat(addTo(copy, rest));
      }
    }

    return result;
  }


  return addTo([], Array.prototype.slice.call(arguments));
}


>> console.log(cartProd([1,2], [10,20], [100,200,300]));
>> [
     [1, 10, 100], [1, 10, 200], [1, 10, 300], [1, 20, 100], 
     [1, 20, 200], [1, 20, 300], [2, 10, 100], [2, 10, 200], 
     [2, 10, 300], [2, 20, 100], [2, 20, 200], [2, 20, 300]
   ]

पूर्ण संदर्भ कार्यान्वयन अपेक्षाकृत कुशल है ...: -डॉ

कार्यकुशलता पर: यदि आप तकनीकी रूप से स्थिर हैं और लूप से बाहर निकलने के बाद आप कुछ अलग-अलग कर सकते हैं और 2 अलग-अलग छोरों को प्राप्त कर सकते हैं, तो आप शाखा भविष्यवाणी और उस गड़बड़ी में मदद करेंगे, लेकिन वह बिंदु जावास्क्रिप्ट में मूट की तरह है

anywho, आनंद -ck


1
आपके विस्तृत उत्तर के लिए धन्यवाद @ckoz। आप reduceसरणी के कार्य का उपयोग क्यों नहीं करेंगे ?
विबेल

1
@viebel आप कम क्यों उपयोग करना चाहते हैं? एक के लिए, पुराने ब्राउज़र के लिए बहुत कम समर्थन है (देखें: developer.mozilla.org/en-US/docs/JavaScript/Reference/… ), और किसी भी मामले में उस पागल कोड से अन्य उत्तर वास्तव में आपके लिए पठनीय लगते हैं ? यह मेरे लिए नहीं है। यकीन है कि यह छोटा है, लेकिन एक बार यह कोड एक समान लंबाई के आसपास होगा, डिबग / ऑप्टिमाइज़ करना आसान होगा, दूसरी बात यह है कि सभी "कम" समाधान एक ही चीज़ के लिए टूट जाते हैं, सिवाय इसके कि उनके पास एक नज़दीकी खोज (सैद्धांतिक रूप से धीमी) हो, यह भी कठिन है डिजाइन करने के लिए इसलिए यह अनंत सेट को संभालता है ...
21

5
मैंने 2+ बार तेज़ और (imo) क्लीनर संस्करण बनाया: pastebin.com/YbhqZuf7 यह प्रयोग न करके result = result.concat(...)और न उपयोग करके गति को बढ़ाता है args.slice(1)। दुर्भाग्य से, मैं छुटकारा पाने curr.slice()और पुनरावृत्ति का रास्ता नहीं खोज पा रहा था ।
पौआं

2
@Pauan अच्छा काम, मैं देख रहा हूँ के आधार पर 10% -50% प्रदर्शन को बढ़ावा देने के लीग में पूरे के लिए हॉट-स्पॉट की अच्छी कमी। मैं "स्वच्छता" के रूप में नहीं बोल सकता, हालांकि, मुझे लगता है कि आपके संस्करण को क्लोजर गुंजाइश चर के उपयोग के कारण वास्तव में पालन करना अधिक कठिन है। लेकिन आम तौर पर, अधिक प्रदर्शन कोड का पालन करना कठिन है। मैंने पठनीयता के लिए मूल संस्करण लिखा, काश मेरे पास और अधिक समय होता ताकि मैं आपको एक प्रदर्शन फेंकने में संलग्न कर पाता;) हो सकता है बाद में ...
ckozl

यह वास्तव में उन समस्याओं में से एक है
जेम्स

26

निम्नलिखित कुशल जनरेटर फ़ंक्शन दिए गए पुनरावृत्तियों के कार्टेशियन उत्पाद को लौटाता है :

// Generate cartesian product of given iterables:
function* cartesian(head, ...tail) {
  const remainder = tail.length > 0 ? cartesian(...tail) : [[]];
  for (let r of remainder) for (let h of head) yield [h, ...r];
}

// Example:
console.log(...cartesian([1, 2], [10, 20], [100, 200, 300]));

यह एररएबल प्रोटोकॉल को लागू करने वाले एरेज़, स्ट्रिंग्स, सेट्स और अन्य सभी ऑब्जेक्ट्स को स्वीकार करता है

एन-एरी कार्टेसियन उत्पाद के विनिर्देशन के बाद इसकी पैदावार होती है

  • []यदि एक या अधिक दिए गए पुनरावृत्तियाँ खाली हैं, उदाहरण के लिए []या''
  • [[a]]यदि एक एकल चलने योग्य एकल मान aदिया जाता है।

निम्नलिखित परीक्षण मामलों द्वारा दिखाए गए अनुसार अन्य सभी मामलों को अपेक्षित रूप से नियंत्रित किया जाता है:


क्या आप यह समझाने के लिए मन बनाते हैं कि इस पर क्या हो रहा है? आपका बहुत बहुत धन्यवाद!
LeandroP

हमें जनरेटर फंक्शन + टेल रिकर्सियन + डबल-लेयर लूप्स का उपयोग करने का एक बहुत बढ़िया उदाहरण सिखाने के लिए धन्यवाद! लेकिन आउटपुट उप-सरणियों के क्रम को सही बनाने के लिए कोड में पहले फॉर-लूप की स्थिति को बदलना होगा। फिक्स्ड कोड:function* cartesian(head, ...tail) { for (let h of head) { const remainder = tail.length > 0 ? cartesian(...tail) : [[]]; for (let r of remainder) yield [h, ...r] } }
ooo

@ooo यदि आप ओपी की टिप्पणी द्वारा दिए गए कार्टेशियन उत्पाद ट्यूपल्स के क्रम को पुन: उत्पन्न करना चाहते हैं, तो आपका संशोधन सही है। हालांकि, उत्पाद के भीतर टुपल्स का क्रम आमतौर पर प्रासंगिक नहीं है, उदाहरण के लिए गणितीय रूप से परिणाम एक अनियंत्रित सेट है। मैंने इस आदेश को चुना क्योंकि इसके लिए बहुत कम पुनरावर्ती कॉल की आवश्यकता होती है और इसलिए यह थोड़ा अधिक प्रदर्शनकारी है - मैंने एक बेंचमार्क नहीं चलाया।
le_m

एराट्रम: ऊपर मेरी टिप्पणी में, "पूंछ पुनरावृत्ति" "पुनरावृत्ति" होनी चाहिए (इस मामले में पूंछ कॉल नहीं)।
ooo

20

यहाँ एक गैर-फैंसी, सीधा पुनरावर्ती समाधान है:

function cartesianProduct(a) { // a = array of array
    var i, j, l, m, a1, o = [];
    if (!a || a.length == 0) return a;

    a1 = a.splice(0, 1)[0]; // the first array of a
    a = cartesianProduct(a);
    for (i = 0, l = a1.length; i < l; i++) {
        if (a && a.length) for (j = 0, m = a.length; j < m; j++)
            o.push([a1[i]].concat(a[j]));
        else
            o.push([a1[i]]);
    }
    return o;
}

console.log(cartesianProduct([[1,2], [10,20], [100,200,300]]));
// [[1,10,100],[1,10,200],[1,10,300],[1,20,100],[1,20,200],[1,20,300],[2,10,100],[2,10,200],[2,10,300],[2,20,100],[2,20,200],[2,20,300]]


2
यह इस विषय के तहत सबसे कुशल शुद्ध जेएस कोड निकला। यह लंबाई 1M की एक सरणी का उत्पादन करने के लिए 3 x 100 आइटम सरणियों पर समाप्त करने के लिए ~ 600msecs की तरह लगता है।
रेडू

1
कार्टेसियनप्रोडक्ट ([[[१]], २], [३]], ['ए ’, [बी’], [[ma गामा ’], [[' अल्फा’]]], [ii ज़ी ’] के लिए काम करता है। 'एफएए']]); मूल मूल्यों के बिना सपाट
Mnn

10

यहाँ एक पुनरावर्ती तरीका है जो एक ECMAScript 2015 जनरेटर फ़ंक्शन का उपयोग करता है ताकि आपको एक बार में सभी tuples बनाने की आवश्यकता न हो:

function* cartesian() {
    let arrays = arguments;
    function* doCartesian(i, prod) {
        if (i == arrays.length) {
            yield prod;
        } else {
            for (let j = 0; j < arrays[i].length; j++) {
                yield* doCartesian(i + 1, prod.concat([arrays[i][j]]));
            }
        }
    }
    yield* doCartesian(0, []);
}

console.log(JSON.stringify(Array.from(cartesian([1,2],[10,20],[100,200,300]))));
console.log(JSON.stringify(Array.from(cartesian([[1],[2]],[10,20],[100,200,300]))));


यह तब काम नहीं करेगा जब किसी एरे में सरणी आइटम हों जैसेcartesian([[1],[2]],[10,20],[100,200,300])
Redu

सरणी तर्क का समर्थन करने के लिए @Redu उत्तर अपडेट किया गया है।
हेनेनी

हां .concat(), प्रसार ऑपरेटर में निर्मित कभी-कभी धोखा हो सकता है।
रेडू

10

यहाँ मूल ES2019 का उपयोग करके एक-लाइनर है flatMap। किसी पुस्तकालय की जरूरत नहीं, बस एक आधुनिक ब्राउज़र (या ट्रांसपिलर):

data.reduce((a, b) => a.flatMap(x => b.map(y => [...x, y])), [[]]);

यह अनिवार्य रूप से वियबेल के उत्तर का एक आधुनिक संस्करण है, बिना लॉश के।


9

ES6 जनरेटर के साथ एक विशिष्ट backtracking का उपयोग कर,

function cartesianProduct(...arrays) {
  let current = new Array(arrays.length);
  return (function* backtracking(index) {
    if(index == arrays.length) yield current.slice();
    else for(let num of arrays[index]) {
      current[index] = num;
      yield* backtracking(index+1);
    }
  })(0);
}
for (let item of cartesianProduct([1,2],[10,20],[100,200,300])) {
  console.log('[' + item.join(', ') + ']');
}
div.as-console-wrapper { max-height: 100%; }

नीचे पुराने ब्राउज़र के साथ संगत समान संस्करण है।


9

यह तीर कार्यों का उपयोग करके एक शुद्ध ES6 समाधान है

function cartesianProduct(arr) {
  return arr.reduce((a, b) =>
    a.map(x => b.map(y => x.concat(y)))
    .reduce((a, b) => a.concat(b), []), [[]]);
}

var arr = [[1, 2], [10, 20], [100, 200, 300]];
console.log(JSON.stringify(cartesianProduct(arr)));


7

लॉश के साथ एक कॉफ़ीस्क्रिप्ट संस्करण:

_ = require("lodash")
cartesianProduct = ->
    return _.reduceRight(arguments, (a,b) ->
        _.flatten(_.map(a,(x) -> _.map b, (y) -> x.concat(y)), true)
    , [ [] ])

7

इंडेंटेशन के साथ बेहतर रीडिंग के लिए सिंगल लाइन अप्रोच।

result = data.reduce(
    (a, b) => a.reduce(
        (r, v) => r.concat(b.map(w => [].concat(v, w))),
        []
    )
);

यह वांछित कार्टेसियन आइटम के सरणियों के साथ एक एकल सरणी लेता है।

var data = [[1, 2], [10, 20], [100, 200, 300]],
    result = data.reduce((a, b) => a.reduce((r, v) => r.concat(b.map(w => [].concat(v, w))), []));

console.log(result.map(a => a.join(' ')));
.as-console-wrapper { max-height: 100% !important; top: 0; }


मुझे उस मामले को सही ढंग से संभालने के लिए एक गार्ड स्टेटमेंट जोड़ना पड़ा जहां एरे में एक ही तत्व है:if (arr.length === 1) return arr[0].map(el => [el]);
जैकबवेलिन

5

यह कार्यात्मक-प्रोग्रामिंग को टैग किया गया है, तो आइए सूची मोनद पर एक नज़र डालें :

इस मौद्रिक सूची के लिए एक आवेदन nondeterministic अभिकलन का प्रतिनिधित्व कर रहा है। एल्गोरिथ्म में List सभी निष्पादन पथ के लिए परिणाम पकड़ सकते हैं ...

अच्छा लगता है कि के लिए एक आदर्श फिट है cartesian। जावास्क्रिप्ट हमें देता है Arrayऔर monadic बाइंडिंग फ़ंक्शन है Array.prototype.flatMap, तो चलो उन्हें उपयोग करने के लिए डालते हैं -

const cartesian = (...all) =>
{ const loop = (t, a, ...more) =>
    a === undefined
      ? [ t ]
      : a .flatMap (x => loop ([ ...t, x ], ...more))
  return loop ([], ...all)
}

console .log (cartesian ([1,2], [10,20], [100,200,300]))

loopउपरोक्त के बजाय , tएक क्यूरेटेड पैरामीटर के रूप में जोड़ा जा सकता है -

const makeCartesian = (t = []) => (a, ...more) =>
  a === undefined
    ? [ t ]
    : a .flatMap (x => makeCartesian ([ ...t, x ]) (...more))

const cartesian =
  makeCartesian ()

console .log (cartesian ([1,2], [10,20], [100,200,300]))


3

इस विषय के अंतर्गत कुछ उत्तर विफल हो जाते हैं जब किसी भी इनपुट सरणियों में एक सरणी आइटम होता है। आप बेहतर है कि जाँच करें।

वैसे भी अंडरस्कोर की कोई आवश्यकता नहीं है, जो भी दर्ज हो। मेरा मानना ​​है कि इसे शुद्ध जेएस ईएस 6 के साथ करना चाहिए, जैसा कि यह कार्यात्मक है।

कोड का यह टुकड़ा एक कम और एक नेस्टेड मैप का उपयोग करता है, बस दो सरणियों के कार्टेसियन उत्पाद को प्राप्त करने के लिए हालांकि दूसरा सरणी एक पुनरावर्ती कॉल से एक ही सरणी में एक कम सरणी के साथ आता है; अत.. a[0].cartesian(...a.slice(1))

Array.prototype.cartesian = function(...a){
  return a.length ? this.reduce((p,c) => (p.push(...a[0].cartesian(...a.slice(1)).map(e => a.length > 1 ? [c,...e] : [c,e])),p),[])
                  : this;
};

var arr = ['a', 'b', 'c'],
    brr = [1,2,3],
    crr = [[9],[8],[7]];
console.log(JSON.stringify(arr.cartesian(brr,crr))); 


3

मेरी विशेष सेटिंग में, "पुराने जमाने" का दृष्टिकोण अधिक आधुनिक सुविधाओं के आधार पर तरीकों की तुलना में अधिक कुशल लग रहा था। नीचे कोड है (इस धागे में @rsp और @sebnukem द्वारा पोस्ट किए गए अन्य समाधानों के साथ एक छोटी तुलना सहित) यह किसी और के लिए भी उपयोगी साबित होना चाहिए।

विचार निम्नलिखित है। मान लें कि हम Nसरणियों के बाहरी उत्पाद का निर्माण कर रहे हैं , a_1,...,a_Nजिनमें से प्रत्येक में m_iघटक हैं। इन सरणियों के बाहरी उत्पाद में M=m_1*m_2*...*m_Nतत्व हैं और हम उनमें से प्रत्येक को एक N-आयामी वेक्टर के साथ पहचान सकते हैं जिनमें से घटक सकारात्मक पूर्णांक हैं और i-th घटक सख्ती से ऊपर से घिरा हुआ है m_i। उदाहरण के लिए, वेक्टर(0, 0, ..., 0) उस विशेष संयोजन के अनुरूप होगा जिसके भीतर प्रत्येक सरणी से पहला तत्व लेता है, जबकि (m_1-1, m_2-1, ..., m_N-1)संयोजन के साथ पहचाना जाता है, जहां प्रत्येक सरणी से अंतिम तत्व लेता है। इस प्रकार सभी के निर्माण के लिएM संयोजनों, नीचे दिए गए फ़ंक्शन लगातार ऐसे सभी वैक्टर का निर्माण करते हैं और उनमें से प्रत्येक के लिए इनपुट सरणियों के तत्वों के संगत संयोजन की पहचान करता है।

function cartesianProduct(){
    const N = arguments.length;

    var arr_lengths = Array(N);
    var digits = Array(N);
    var num_tot = 1;
    for(var i = 0; i < N; ++i){
        const len = arguments[i].length;
        if(!len){
            num_tot = 0;
            break;
        }
        digits[i] = 0;
        num_tot *= (arr_lengths[i] = len);
    }

    var ret = Array(num_tot);
    for(var num = 0; num < num_tot; ++num){

        var item = Array(N);
        for(var j = 0; j < N; ++j){ item[j] = arguments[j][digits[j]]; }
        ret[num] = item;

        for(var idx = 0; idx < N; ++idx){
            if(digits[idx] == arr_lengths[idx]-1){
                digits[idx] = 0;
            }else{
                digits[idx] += 1;
                break;
            }
        }
    }
    return ret;
}
//------------------------------------------------------------------------------
let _f = (a, b) => [].concat(...a.map(a => b.map(b => [].concat(a, b))));
let cartesianProduct_rsp = (a, b, ...c) => b ? cartesianProduct_rsp(_f(a, b), ...c) : a;
//------------------------------------------------------------------------------
function cartesianProduct_sebnukem(a) {
    var i, j, l, m, a1, o = [];
    if (!a || a.length == 0) return a;

    a1 = a.splice(0, 1)[0];
    a = cartesianProduct_sebnukem(a);
    for (i = 0, l = a1.length; i < l; i++) {
        if (a && a.length) for (j = 0, m = a.length; j < m; j++)
            o.push([a1[i]].concat(a[j]));
        else
            o.push([a1[i]]);
    }
    return o;
}
//------------------------------------------------------------------------------
const L = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
const args = [L, L, L, L, L, L];

let fns = {
    'cartesianProduct': function(args){ return cartesianProduct(...args); },
    'cartesianProduct_rsp': function(args){ return cartesianProduct_rsp(...args); },
    'cartesianProduct_sebnukem': function(args){ return cartesianProduct_sebnukem(args); }
};

Object.keys(fns).forEach(fname => {
    console.time(fname);
    const ret = fns[fname](args);
    console.timeEnd(fname);
});

के साथ node v6.12.2, मुझे निम्नलिखित समय मिलता है:

cartesianProduct: 427.378ms
cartesianProduct_rsp: 1710.829ms
cartesianProduct_sebnukem: 593.351ms

3

उन लोगों के लिए जिन्हें टाइपस्क्रिप्ट की आवश्यकता है (@ डैनी का उत्तर लागू किया गया)

/**
 * Calculates "Cartesian Product" sets.
 * @example
 *   cartesianProduct([[1,2], [4,8], [16,32]])
 *   Returns:
 *   [
 *     [1, 4, 16],
 *     [1, 4, 32],
 *     [1, 8, 16],
 *     [1, 8, 32],
 *     [2, 4, 16],
 *     [2, 4, 32],
 *     [2, 8, 16],
 *     [2, 8, 32]
 *   ]
 * @see https://stackoverflow.com/a/36234242/1955709
 * @see https://en.wikipedia.org/wiki/Cartesian_product
 * @param arr {T[][]}
 * @returns {T[][]}
 */
function cartesianProduct<T> (arr: T[][]): T[][] {
  return arr.reduce((a, b) => {
    return a.map(x => {
      return b.map(y => {
        return x.concat(y)
      })
    }).reduce((c, d) => c.concat(d), [])
  }, [[]] as T[][])
}

2

बस एक विकल्प के लिए एक वास्तविक सरल कार्यान्वयन है सरणी का उपयोग reduce:

const array1 = ["day", "month", "year", "time"];
const array2 = ["from", "to"];
const process = (one, two) => [one, two].join(" ");

const product = array1.reduce((result, one) => result.concat(array2.map(two => process(one, two))), []);

2

कुछ ही लाइनों में आधुनिक जावास्क्रिप्ट। कोई बाहरी पुस्तकालय या लोदश जैसी निर्भरता नहीं।

function cartesian(...arrays) {
  return arrays.reduce((a, b) => a.flatMap(x => b.map(y => x.concat([y]))), [ [] ]);
}

console.log(
  cartesian([1, 2], [10, 20], [100, 200, 300])
    .map(arr => JSON.stringify(arr))
    .join('\n')
);


2

आप reduce2 डी सरणी कर सकते हैं । प्रत्येक लूप में संयोजनों की संख्या flatMapप्राप्त करने के लिए संचायक सरणी पर उपयोग करें acc.length x curr.length[].concat(c, n)उपयोग किया जाता है क्योंकि cपहले पुनरावृत्ति में एक संख्या और बाद में एक सरणी है।

const data = [ [1, 2], [10, 20], [100, 200, 300] ];

const output = data.reduce((acc, curr) =>
  acc.flatMap(c => curr.map(n => [].concat(c, n)))
)

console.log(JSON.stringify(output))

(यह नीना शोल्ज़ के उत्तर पर आधारित है )


1

एक गैर-पुनरावर्ती दृष्टिकोण जो वास्तव में परिणाम सेट में जोड़ने से पहले उत्पादों को फ़िल्टर और संशोधित करने की क्षमता को जोड़ता है। .ForEach के बजाय .map के उपयोग पर ध्यान दें। कुछ ब्राउज़रों में .map तेजी से चलता है।

function crossproduct(arrays,rowtest,rowaction) {
      // Calculate the number of elements needed in the result
      var result_elems = 1, row_size = arrays.length;
      arrays.map(function(array) {
            result_elems *= array.length;
      });
      var temp = new Array(result_elems), result = [];

      // Go through each array and add the appropriate element to each element of the temp
      var scale_factor = result_elems;
      arrays.map(function(array)
      {
        var set_elems = array.length;
        scale_factor /= set_elems;
        for(var i=result_elems-1;i>=0;i--) {
            temp[i] = (temp[i] ? temp[i] : []);
            var pos = i / scale_factor % set_elems;
            // deal with floating point results for indexes, this took a little experimenting
            if(pos < 1 || pos % 1 <= .5) {
                pos = Math.floor(pos);
            } else {
                pos = Math.min(array.length-1,Math.ceil(pos));
            }
            temp[i].push(array[pos]);
            if(temp[i].length===row_size) {
                var pass = (rowtest ? rowtest(temp[i]) : true);
                if(pass) {
                    if(rowaction) {
                        result.push(rowaction(temp[i]));
                    } else {
                        result.push(temp[i]);
                    }
                }
            }
        }
      });
      return result;
    }

1

एक सरल "मन और नेत्रहीन अनुकूल" समाधान।

यहां छवि विवरण दर्ज करें


// t = [i, length]

const moveThreadForwardAt = (t, tCursor) => {
  if (tCursor < 0)
    return true; // reached end of first array

  const newIndex = (t[tCursor][0] + 1) % t[tCursor][1];
  t[tCursor][0] = newIndex;

  if (newIndex == 0)
    return moveThreadForwardAt(t, tCursor - 1);

  return false;
}

const cartesianMult = (...args) => {
  let result = [];
  const t = Array.from(Array(args.length)).map((x, i) => [0, args[i].length]);
  let reachedEndOfFirstArray = false;

  while (false == reachedEndOfFirstArray) {
    result.push(t.map((v, i) => args[i][v[0]]));

    reachedEndOfFirstArray = moveThreadForwardAt(t, args.length - 1);
  }

  return result;
}

// cartesianMult(
//   ['a1', 'b1', 'c1'],
//   ['a2', 'b2'],
//   ['a3', 'b3', 'c3'],
//   ['a4', 'b4']
// );

console.log(cartesianMult(
  ['a1'],
  ['a2', 'b2'],
  ['a3', 'b3']
));

1

सादे जावास्क्रिप्ट में @ viebel के कोड का एक सरल, संशोधित संस्करण:

function cartesianProduct(...arrays) {
  return arrays.reduce((a, b) => {
    return [].concat(...a.map(x => {
      const next = Array.isArray(x) ? x : [x];
      return [].concat(b.map(y => next.concat(...[y])));
    }));
  });
}

const product = cartesianProduct([1, 2], [10, 20], [100, 200, 300]);

console.log(product);
/*
[ [ 1, 10, 100 ],
  [ 1, 10, 200 ],
  [ 1, 10, 300 ],
  [ 1, 20, 100 ],
  [ 1, 20, 200 ],
  [ 1, 20, 300 ],
  [ 2, 10, 100 ],
  [ 2, 10, 200 ],
  [ 2, 10, 300 ],
  [ 2, 20, 100 ],
  [ 2, 20, 200 ],
  [ 2, 20, 300 ] ];
*/

1

एक अधिक पठनीय कार्यान्वयन

function productOfTwo(one, two) {
  return one.flatMap(x => two.map(y => [].concat(x, y)));
}

function product(head = [], ...tail) {
  if (tail.length === 0) return head;
  return productOfTwo(head, product(...tail));
}

const test = product(
  [1, 2, 3],
  ['a', 'b']
);

console.log(JSON.stringify(test));


1
f=(a,b,c)=>a.flatMap(ai=>b.flatMap(bi=>c.map(ci=>[ai,bi,ci])))

यह 3 सरणियों के लिए है।
कुछ उत्तरों ने किसी भी संख्या में सरणियों के लिए एक रास्ता दिया।
यह कम या अधिक सरणियों को आसानी से अनुबंधित या विस्तारित कर सकता है।
मुझे पुनरावृत्तियों के साथ एक सेट के संयोजन की आवश्यकता थी, इसलिए मैं इसका उपयोग कर सकता था:

f(a,a,a)

लेकिन इस्तेमाल किया:

f=(a,b,c)=>a.flatMap(a1=>a.flatMap(a2=>a.map(a3=>[a1,a2,a3])))

0

मैंने देखा कि कोई भी एक समाधान पोस्ट नहीं करता है जो प्रत्येक संयोजन को संसाधित करने के लिए फ़ंक्शन को पारित करने की अनुमति देता है, इसलिए यहां मेरा समाधान है:

const _ = require('lodash')

function combinations(arr, f, xArr = []) {
    return arr.length>1 
    ? _.flatMap(arr[0], x => combinations(arr.slice(1), f, xArr.concat(x)))
    : arr[0].map(x => f(...xArr.concat(x)))
}

// use case
const greetings = ["Hello", "Goodbye"]
const places = ["World", "Planet"]
const punctuationMarks = ["!", "?"]
combinations([greetings,places,punctuationMarks], (greeting, place, punctuationMark) => `${greeting} ${place}${punctuationMark}`)
  .forEach(row => console.log(row))

आउटपुट:

Hello World!
Hello World?
Hello Planet!
Hello Planet?
Goodbye World!
Goodbye World?
Goodbye Planet!
Goodbye Planet?

0

सादा जेएस जानवर बल दृष्टिकोण जो इनपुट के रूप में सरणियों की एक सरणी लेता है।

var cartesian = function(arrays) {
    var product = [];
    var precals = [];
    var length = arrays.reduce(function(acc, curr) {
        return acc * curr.length
    }, 1);
    for (var i = 0; i < arrays.length; i++) {
        var array = arrays[i];
        var mod = array.length;
        var div = i > 0 ? precals[i - 1].div * precals[i - 1].mod : 1;
        precals.push({
            div: div,
            mod: mod
        });
    }
    for (var j = 0; j < length; j++) {
        var item = [];
        for (var i = 0; i < arrays.length; i++) {
            var array = arrays[i];
            var precal = precals[i];
            var k = (~~(j / precal.div)) % precal.mod;
            item.push(array[k]);
        }
        product.push(item);
    }
    return product;
};

cartesian([
    [1],
    [2, 3]
]);

cartesian([
    [1],
    [2, 3],
    [4, 5, 6]
]);

0

var chars = ['A', 'B', 'C']
var nums = [1, 2, 3]

var cartesianProduct = function() {
  return _.reduce(arguments, function(a, b) {
    return _.flatten(_.map(a, function(x) {
      return _.map(b, function(y) {
        return x.concat(y);
      });
    }), true);
  }, [
    []
  ]);
};

console.log(cartesianProduct(chars, nums))
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>

बस कॉफ़ेस्क्रिप्ट से जावास्क्रिप्ट में @ dummersl के उत्तर को रूपांतरित किया। यह सिर्फ काम करता है।

var chars = ['A', 'B', 'C']
var nums = [1, 2, 3]

var cartesianProduct = function() {
  return _.reduce(arguments, function(a, b) {
    return _.flatten(_.map(a, function(x) {
      return _.map(b, function(y) {
        return x.concat(y);
      });
    }), true);
  }, [[]]);
};

console.log( cartesianProduct(chars, nums) )

0

फिर भी एक और कार्यान्वयन। सबसे छोटा या फैंसी नहीं, लेकिन तेज:

function cartesianProduct() {
    var arr = [].slice.call(arguments),
        intLength = arr.length,
        arrHelper = [1],
        arrToReturn = [];

    for (var i = arr.length - 1; i >= 0; i--) {
        arrHelper.unshift(arrHelper[0] * arr[i].length);
    }

    for (var i = 0, l = arrHelper[0]; i < l; i++) {
        arrToReturn.push([]);
        for (var j = 0; j < intLength; j++) {
            arrToReturn[i].push(arr[j][(i / arrHelper[j + 1] | 0) % arr[j].length]);
        }
    }

    return arrToReturn;
}

0

कोई पुस्तकालयों की जरूरत है! :)

हालांकि यह संभव नहीं है कि तीर कार्यों की जरूरत है। : /

const flatten = (xs) => 
    xs.flat(Infinity)

const binaryCartesianProduct = (xs, ys) =>
    xs.map((xi) => ys.map((yi) => [xi, yi])).flat()

const cartesianProduct = (...xss) =>
    xss.reduce(binaryCartesianProduct, [[]]).map(flatten)
      
console.log(cartesianProduct([1,2,3], [1,2,3], [1,2,3]))


0

रिकार्ड के लिए

यहाँ यह मेरा संस्करण है। मैंने इसे "()" के लिए सबसे सरल जावास्क्रिप्ट इटेटर का उपयोग करके बनाया है, इसलिए यह हर मामले पर संगत है और इसमें सबसे अच्छा प्रदर्शन है।

function cartesian(arrays){
    var quant = 1, counters = [], retArr = [];

    // Counts total possibilities and build the counters Array;
    for(var i=0;i<arrays.length;i++){
        counters[i] = 0;
        quant *= arrays[i].length;
    }

    // iterate all possibilities
    for(var i=0,nRow;i<quant;i++){
        nRow = [];
        for(var j=0;j<counters.length;j++){
            if(counters[j] < arrays[j].length){
                nRow.push(arrays[j][counters[j]]);
            } else { // in case there is no such an element it restarts the current counter
                counters[j] = 0;
                nRow.push(arrays[j][counters[j]]);
            }
            counters[j]++;
        }
        retArr.push(nRow);
    }
    return retArr;
}

सादर।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.