एक जावास्क्रिप्ट पुनरावृत्ति को एक सरणी में बदलना


171

मैं जावास्क्रिप्ट ईसी 6 से नई मैप ऑब्जेक्ट का उपयोग करने की कोशिश कर रहा हूं , क्योंकि यह पहले से ही नवीनतम फ़ायरफ़ॉक्स और क्रोम संस्करणों में समर्थित है।

लेकिन मैं इसे "कार्यात्मक" प्रोग्रामिंग में बहुत सीमित पा रहा हूं, क्योंकि इसमें क्लासिक मैप, फिल्टर आदि तरीकों का अभाव है जो एक [key, value]जोड़ी के साथ अच्छी तरह से काम करेंगे । इसमें एक forEach है लेकिन यह कॉलबैक परिणाम नहीं देता है।

अगर मैं map.entries()एक MapIterator से एक साधारण ऐरे में बदल सकता हूं तो मैं मानक का उपयोग कर सकता हूं .map, .filterजिसमें कोई अतिरिक्त हैक नहीं है।

वहाँ एक जावास्क्रिप्ट में एक जावास्क्रिप्ट को बदलने के लिए एक "अच्छा" तरीका है? अजगर में यह करना जितना आसान है list(iterator)... लेकिन Array(m.entries())इसके पहले तत्व के रूप में इटरेटर के साथ एक सरणी लौटाएं !!!

संपादित करें

मैं यह निर्दिष्ट करना भूल गया कि मैं एक ऐसे उत्तर की तलाश कर रहा हूं जो जहां भी काम करता है, उसका अर्थ है कि कम से कम क्रोम और फ़ायरफ़ॉक्स (Array.from क्रोम में काम नहीं करता है)।

पुनश्च।

मुझे पता है कि शानदार wu.js है, लेकिन ट्रेसुर पर इसकी निर्भरता मुझे दूर करती है ...


यह भी देखें stackoverflow.com/q/27612713/1460043
user1460043

जवाबों:


247

आप नए Array.fromफ़ंक्शन की तलाश कर रहे हैं जो मनमाने ढंग से पुनरावृत्तियों को सरणी उदाहरणों में परिवर्तित करता है:

var arr = Array.from(map.entries());

यह अब एज, एफएफ, क्रोम और नोड 4+ में समर्थित है

बेशक, यह परिभाषित करने के लिए लायक हो सकता है map, filterऔर इसी तरह के तरीके सीधे इटोमर इंटरफ़ेस पर, ताकि आप सरणी को आवंटित करने से बच सकें। आप उच्च-क्रम के कार्यों के बजाय एक जनरेटर फ़ंक्शन का उपयोग करना चाहते हैं:

function* map(iterable) {
    var i = 0;
    for (var item of iterable)
        yield yourTransformation(item, i++);
}
function* filter(iterable) {
    var i = 0;
    for (var item of iterable)
        if (yourPredicate(item, i++))
             yield item;
}

मुझे उम्मीद है कि कॉलबैक में (value, key)जोड़े और (value, index)जोड़े नहीं मिलेंगे ।
आदित एम शाह

3
@AaditMShah: एक पुनरावृत्ति की कुंजी क्या है? बेशक, यदि आप एक नक्शे को पुनरावृत्त करते हैं, तो आप परिभाषित कर सकते हैंyourTransformation = function([key, value], index) { … }
बरगी

एक पुनरावृत्ति कुंजी नहीं है, लेकिन एक Mapमहत्वपूर्ण मूल्य जोड़े हैं। इसलिए, मेरी विनम्र राय में, यह सामान्य बनाने mapऔर filterपुनरावृत्तियों के लिए कार्यों को परिभाषित करने का कोई मतलब नहीं है। इसके बजाय, प्रत्येक चलने योग्य वस्तु का अपना mapऔर filterकार्य होना चाहिए । यह समझ में आता है क्योंकि mapऔर filterसंरचना के संरक्षण के संचालन हैं (शायद नहीं, filterलेकिन mapनिश्चित रूप से है) और इसलिए कार्यों mapऔर filterकार्यों को उन चलने योग्य वस्तुओं की संरचना को जानना चाहिए जिन्हें वे मैप कर रहे हैं या फ़िल्टर कर रहे हैं। इसके बारे में सोचें, हास्केल में हम विभिन्न उदाहरणों को परिभाषित करते हैं Functor। =)
आदित एम शाह

1
@ सेफ़ानो: आप इसे आसानी से देख सकते हैं ...
बर्गी

1
@Incognito आह ठीक है, यकीन है कि यह सच है, लेकिन यह वही है जो सवाल पूछ रहा है, मेरे जवाब के साथ कोई समस्या नहीं है।
बरगी

45

[...map.entries()] या Array.from(map.entries())

यह सुपर आसान है।

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


1
जब तक आपके पास कुछ अधिक पर्याप्त न हो, यह वास्तव में एक टिप्पणी होनी चाहिए। इसके अलावा, Array.fromपहले से ही @Bergi द्वारा कवर किया गया है।
आदित एम शाह

2
और, जैसा कि मैंने अपने मूल प्रश्न में लिखा था, [iterator]काम नहीं करता क्योंकि क्रोम में यह एक एकल iteratorतत्व के साथ एक सरणी बनाता है, और [...map.entries()]क्रोम में एक स्वीकृत वाक्यविन्यास नहीं है
स्टेफानो

2
@Stefano स्प्रेड ऑपरेटर को अब क्रोम
केलसुन

15

Mapमें बदलने की जरूरत नहीं है Array। आप बस वस्तुओं के लिए बना सकते हैं mapऔर filterकार्य कर सकते Mapहैं:

function map(functor, object, self) {
    var result = new Map;

    object.forEach(function (value, key, object) {
        result.set(key, functor.call(this, value, key, object));
    }, self);

    return result;
}

function filter(predicate, object, self) {
    var result = new Map;

    object.forEach(function (value, key, object) {
        if (predicate.call(this, value, key, object)) result.set(key, value);
    }, self);

    return result;
}

उदाहरण के लिए, आप !मानचित्र के प्रत्येक प्रविष्टि के मूल्य के लिए एक बैंग (यानी वर्ण) जोड़ सकते हैं जिसकी कुंजी एक आदिम है।

var object = new Map;

object.set("", "empty string");
object.set(0,  "number zero");
object.set(object, "itself");

var result = map(appendBang, filter(primitive, object));

alert(result.get(""));     // empty string!
alert(result.get(0));      // number zero!
alert(result.get(object)); // undefined

function primitive(value, key) {
    return isPrimitive(key);
}

function appendBang(value) {
    return value + "!";
}

function isPrimitive(value) {
    var type = typeof value;
    return value === null ||
        type !== "object" &&
        type !== "function";
}
<script>
function map(functor, object, self) {
    var result = new Map;

    object.forEach(function (value, key, object) {
        result.set(key, functor.call(this, value, key, object));
    }, self || null);

    return result;
}

function filter(predicate, object, self) {
    var result = new Map;

    object.forEach(function (value, key, object) {
        if (predicate.call(this, value, key, object)) result.set(key, value);
    }, self || null);

    return result;
}
</script>

आप इसे बेहतर तरीके से पढ़ने के लिए mapऔर filterतरीके भी जोड़ सकते हैं Map.prototype। हालांकि आमतौर पर देशी प्रोटोटाइप को संशोधित करने की सलाह नहीं दी जाती है, फिर भी मेरा मानना ​​है कि इसके मामले में mapऔर इसके filterलिए एक अपवाद बनाया जा सकता है Map.prototype:

var object = new Map;

object.set("", "empty string");
object.set(0,  "number zero");
object.set(object, "itself");

var result = object.filter(primitive).map(appendBang);

alert(result.get(""));     // empty string!
alert(result.get(0));      // number zero!
alert(result.get(object)); // undefined

function primitive(value, key) {
    return isPrimitive(key);
}

function appendBang(value) {
    return value + "!";
}

function isPrimitive(value) {
    var type = typeof value;
    return value === null ||
        type !== "object" &&
        type !== "function";
}
<script>
Map.prototype.map = function (functor, self) {
    var result = new Map;

    this.forEach(function (value, key, object) {
        result.set(key, functor.call(this, value, key, object));
    }, self || null);

    return result;
};

Map.prototype.filter = function (predicate, self) {
    var result = new Map;

    this.forEach(function (value, key, object) {
        if (predicate.call(this, value, key, object)) result.set(key, value);
    }, self || null);

    return result;
};
</script>


संपादित करें: बर्गी के जवाब में, उन्होंने सभी पुनरावृत्त वस्तुओं के लिए सामान्य mapऔर filterजनरेटर कार्यों का निर्माण किया। उनका उपयोग करने का लाभ यह है कि चूंकि वे जनरेटर के कार्य हैं, इसलिए वे मध्यवर्ती चलने योग्य वस्तुओं को आवंटित नहीं करते हैं।

उदाहरण के लिए, ऊपर वर्णित मेरी mapऔर filterफ़ंक्शन नई Mapऑब्जेक्ट बनाते हैं। इसलिए बुला रहा हैobject.filter(primitive).map(appendBang) दो नई Mapऑब्जेक्ट बनाता है :

var intermediate = object.filter(primitive);
var result = intermediate.map(appendBang);

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

बर्गी के जनरेटर कार्यों के साथ एकमात्र समस्या यह है कि वे Mapवस्तुओं के लिए विशिष्ट नहीं हैं। इसके बजाय, वे सभी पुनरावृत्त वस्तुओं के लिए सामान्यीकृत हैं। इसलिए कॉलबैक फ़ंक्शन के साथ कॉल करने के बजाय(value, key) जोड़े के (जैसा कि मैं मैपिंग के दौरान उम्मीद करूंगा Map), यह कॉलबैक फ़ंक्शन को (value, index)जोड़े के साथ कॉल करता है । अन्यथा, यह एक उत्कृष्ट समाधान है और मैं निश्चित रूप से उन समाधानों का उपयोग करने की सिफारिश करूंगा जो मैंने प्रदान किए थे।

इसलिए ये विशिष्ट जनरेटर फ़ंक्शन हैं जिनका उपयोग मैं Mapऑब्जेक्ट्स को मैप करने और फ़िल्टर करने के लिए करूंगा :

function * map(functor, entries, self) {
    var that = self || null;

    for (var entry of entries) {
        var key   = entry[0];
        var value = entry[1];

        yield [key, functor.call(that, value, key, entries)];
    }
}

function * filter(predicate, entries, self) {
    var that = self || null;

    for (var entry of entries) {
        var key    = entry[0];
        var value  = entry[1];

        if (predicate.call(that, value, key, entries)) yield [key, value];
    }
}

function toMap(entries) {
    var result = new Map;

    for (var entry of entries) {
        var key   = entry[0];
        var value = entry[1];

        result.set(key, value);
    }

    return result;
}

function toArray(entries) {
    var array = [];

    for (var entry of entries) {
        array.push(entry[1]);
    }

    return array;
}

उनका उपयोग निम्नानुसार किया जा सकता है:

var object = new Map;

object.set("", "empty string");
object.set(0,  "number zero");
object.set(object, "itself");

var result = toMap(map(appendBang, filter(primitive, object.entries())));

alert(result.get(""));     // empty string!
alert(result.get(0));      // number zero!
alert(result.get(object)); // undefined

var array  = toArray(map(appendBang, filter(primitive, object.entries())));

alert(JSON.stringify(array, null, 4));

function primitive(value, key) {
    return isPrimitive(key);
}

function appendBang(value) {
    return value + "!";
}

function isPrimitive(value) {
    var type = typeof value;
    return value === null ||
        type !== "object" &&
        type !== "function";
}
<script>
function * map(functor, entries, self) {
    var that = self || null;

    for (var entry of entries) {
        var key   = entry[0];
        var value = entry[1];

        yield [key, functor.call(that, value, key, entries)];
    }
}

function * filter(predicate, entries, self) {
    var that = self || null;

    for (var entry of entries) {
        var key    = entry[0];
        var value  = entry[1];

        if (predicate.call(that, value, key, entries)) yield [key, value];
    }
}

function toMap(entries) {
    var result = new Map;

    for (var entry of entries) {
        var key   = entry[0];
        var value = entry[1];

        result.set(key, value);
    }

    return result;
}

function toArray(entries) {
    var array = [];

    for (var entry of entries) {
        array.push(entry[1]);
    }

    return array;
}
</script>

यदि आप अधिक धाराप्रवाह इंटरफ़ेस चाहते हैं तो आप कुछ इस तरह से कर सकते हैं:

var object = new Map;

object.set("", "empty string");
object.set(0,  "number zero");
object.set(object, "itself");

var result = new MapEntries(object).filter(primitive).map(appendBang).toMap();

alert(result.get(""));     // empty string!
alert(result.get(0));      // number zero!
alert(result.get(object)); // undefined

var array  = new MapEntries(object).filter(primitive).map(appendBang).toArray();

alert(JSON.stringify(array, null, 4));

function primitive(value, key) {
    return isPrimitive(key);
}

function appendBang(value) {
    return value + "!";
}

function isPrimitive(value) {
    var type = typeof value;
    return value === null ||
        type !== "object" &&
        type !== "function";
}
<script>
MapEntries.prototype = {
    constructor: MapEntries,
    map: function (functor, self) {
        return new MapEntries(map(functor, this.entries, self), true);
    },
    filter: function (predicate, self) {
        return new MapEntries(filter(predicate, this.entries, self), true);
    },
    toMap: function () {
        return toMap(this.entries);
    },
    toArray: function () {
        return toArray(this.entries);
    }
};

function MapEntries(map, entries) {
    this.entries = entries ? map : map.entries();
}

function * map(functor, entries, self) {
    var that = self || null;

    for (var entry of entries) {
        var key   = entry[0];
        var value = entry[1];

        yield [key, functor.call(that, value, key, entries)];
    }
}

function * filter(predicate, entries, self) {
    var that = self || null;

    for (var entry of entries) {
        var key    = entry[0];
        var value  = entry[1];

        if (predicate.call(that, value, key, entries)) yield [key, value];
    }
}

function toMap(entries) {
    var result = new Map;

    for (var entry of entries) {
        var key   = entry[0];
        var value = entry[1];

        result.set(key, value);
    }

    return result;
}

function toArray(entries) {
    var array = [];

    for (var entry of entries) {
        array.push(entry[1]);
    }

    return array;
}
</script>

उम्मीद है की वो मदद करदे।


यह धन्यवाद करता है! @Bergi को अच्छा उत्तर चिह्न देते हुए, क्योंकि मैं "Array.from" नहीं जानता था और यह बात उत्तर के लिए सबसे अधिक है। आप के बीच बहुत दिलचस्प चर्चा हालांकि!
स्टेफानो

1
@Stefano मैंने अपने उत्तर को यह दिखाने के लिए संपादित किया कि कैसे जनरेटर Mapका उपयोग विशेष mapऔर filterफ़ंक्शंस का उपयोग करके वस्तुओं को सही ढंग से बदलने के लिए किया जा सकता है । बर्गी का उत्तर सभी पुनरावृत्त वस्तुओं के लिए जेनेरिक mapऔर filterफ़ंक्शंस के उपयोग को प्रदर्शित करता है जिनका उपयोग ऑब्जेक्ट को बदलने के लिए नहीं किया जा सकता Mapक्योंकि ऑब्जेक्ट की कुंजी Mapखो जाती है।
आदित एम शाह

वाह, मुझे वास्तव में आपका संपादन पसंद है। मैंने अपना जवाब यहां लिखना समाप्त कर दिया: stackoverflow.com/a/28721418/422670 (इस प्रश्न के बाद से वहाँ जोड़ा गया है क्योंकि यह डुप्लिकेट के रूप में बंद हो गया है) क्योंकि Array.fromक्रोम में काम नहीं करता है (जबकि नक्शा और पुनरावृत्तियाँ करते हैं!)। लेकिन मैं देख सकता हूं कि दृष्टिकोण बहुत समान है और आप अपने गुच्छा में "एअरर" फ़ंक्शन जोड़ सकते हैं!
स्टेफानो

1
@ सत्तेफानो वास्तव में। मैंने एक toArrayफ़ंक्शन को जोड़ने का तरीका दिखाने के लिए अपना जवाब संपादित किया ।
आदित एम शाह

7

2019 से एक छोटा सा अपडेट:

अब Array.from सार्वभौमिक रूप से उपलब्ध प्रतीत होता है, और, इसके अलावा, यह एक दूसरे तर्क मानचित्र को स्वीकार करता है , जो इसे एक मध्यवर्ती सरणी बनाने से रोकता है। यह मूल रूप से इस तरह दिखता है:

Array.from(myMap.entries(), entry => {...});

चूँकि Array.fromपहले से मौजूद उत्तर के साथ , यह टिप्पणी के लिए अधिक उपयुक्त है या उस उत्तर को संपादित करने का अनुरोध किया है ... लेकिन धन्यवाद!
स्टेफानो

1

आप https://www.npmjs.com/package/itiriri जैसी लाइब्रेरी का उपयोग कर सकते हैं जो पुनरावृत्तियों के लिए सरणी-जैसी विधियों को लागू करता है:

import { query } from 'itiriri';

const map = new Map();
map.set(1, 'Alice');
map.set(2, 'Bob');

const result = query(map)
  .filter([k, v] => v.indexOf('A') >= 0)
  .map([k, v] => `k - ${v.toUpperCase()}`);

for (const r of result) {
  console.log(r); // prints: 1 - ALICE
}

यह परिश्रम अद्भुत लगता है और iterables @dimadeveatii पर कूदने के लिए लापता कन्डिट - इसे लिखने के लिए बहुत बहुत धन्यवाद, मैं इसे जल्द ही
आजमाऊंगा

0

आप सरणियों का सरणी (कुंजी और मूल्य) प्राप्त कर सकते हैं :

[...this.state.selected.entries()]
/**
*(2) [Array(2), Array(2)]
*0: (2) [2, true]
*1: (2) [3, true]
*length: 2
*/

और फिर, आप आसानी से अंदर से मान प्राप्त कर सकते हैं, उदाहरण के लिए नक्शे के साथ कुंजी।

[...this.state.selected[asd].entries()].map(e=>e[0])
//(2) [2, 3]

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