.Map () এ কোনও উপাদান ছাড়বেন কীভাবে?


416

আমি কীভাবে একটি অ্যারে উপাদান এড়িয়ে যেতে পারি .map?

আমার কোড:

var sources = images.map(function (img) {
    if(img.src.split('.').pop() === "json"){ // if extension is .json
        return null; // skip
    }
    else{
        return img.src;
    }
});

এটি ফিরে আসবে:

["img.png", null, "img.png"]

18
আপনি পারবেন না তবে আপনি পরে সমস্ত নাল মান ফিল্টার করতে পারবেন।
ফেলিক্স ক্লিং

1
কেন না? আমি জানি যে ব্যবহার অব্যাহত রাখে না কাজ করে তবে কেন (ডাবল লুপিং এড়ানো হবে) - এডিট করা জেনে রাখা ভাল - আপনার ক্ষেত্রে আপনি যদি কেবলমাত্র শর্তটি পরিবর্তন করতে পারবেন না এবং কেবল img.srcবিভক্ত পপের ফলাফল হলেই ফিরে আসতে পারবেন ! = = জসন?
গ্রেডফক্স

@GrayedFox তারপর অন্তর্নিহিত undefinedপরিবর্তে, এরে পুরা হবে null। এর চেয়ে ভাল নয় ...
এফজেডস

উত্তর:


637

শুধু .filter()এটি প্রথম:

var sources = images.filter(function(img) {
  if (img.src.split('.').pop() === "json") {
    return false; // skip
  }
  return true;
}).map(function(img) { return img.src; });

যদি আপনি এটি করতে না চান, যা কিছুটা ব্যয়যুক্ত হওয়ার কারণে অযৌক্তিক নয়, আপনি আরও সাধারণ ব্যবহার করতে পারেন .reduce()। আপনি সাধারণত .map()শর্তাবলী প্রকাশ করতে পারেন .reduce:

someArray.map(function(element) {
  return transform(element);
});

হিসাবে লেখা যেতে পারে

someArray.reduce(function(result, element) {
  result.push(transform(element));
  return result;
}, []);

সুতরাং আপনার যদি উপাদানগুলি এড়িয়ে চলার দরকার হয় তবে আপনি এটির সাহায্যে সহজেই এটি করতে পারেন .reduce():

var sources = images.reduce(function(result, img) {
  if (img.src.split('.').pop() !== "json") {
    result.push(img.src);
  }
  return result;
}, []);

এই সংস্করণে, .filter()প্রথম নমুনা থেকে প্রাপ্ত কোডটি .reduce()কলব্যাকের অংশ । ফিল্টার অপারেশনটি যেখানে রেখেছিল সেই ক্ষেত্রে চিত্রের উত্সটি কেবলমাত্র ফলাফল অ্যারেতে ঠেলাঠেলি করা হয়।


21
এটির জন্য আপনার পুরো অ্যারে দুটিবার লুপ করার প্রয়োজন নেই? তা এড়ানোর কোনও উপায় আছে কি?
অ্যালেক্স ম্যাকমিলান

7
@ অ্যালেক্স ম্যাকমিলান আপনি .reduce()এটি একটি পাসে ব্যবহার করতে এবং করতে পারতেন , যদিও পারফরম্যান্স- ভিত্তিতে আমি সন্দেহ করি এটি একটি উল্লেখযোগ্য পার্থক্য করতে চাই।
পয়েন্টি

9
এই সমস্ত নেতিবাচক সঙ্গে, "খালি" -style মান ( null, undefined, NaNযদি আমরা একটি ভিতরে এক কাজে লাগাতে পারে ইত্যাদি) এটা ভাল হবে map()একটি সূচক যে এই বস্তু কিছুই মানচিত্র এবং এড়ানো হবে হিসাবে। আমি প্রায়শই 98% এর মানচিত্র তৈরি করতে চাই এমন অ্যারেগুলি জুড়ে আসি (যেমন: String.split()শেষে একটি একক, খালি স্ট্রিং রেখে যা আমি যত্ন করি না)। আপনার উত্তরের জন্য ধন্যবাদ :)
অ্যালেক্স ম্যাকমিলান

6
@ অ্যালেক্সম্যাকমিলান হ'ল বেসলাইনটি .reduce()"আপনার যা ইচ্ছা তাই করুন" ফাংশনটি সাজানো, কারণ রিটার্ন ভ্যালুতে আপনার সম্পূর্ণ নিয়ন্ত্রণ রয়েছে। ট্রান্সডুসারদের ধারণা সম্পর্কে ক্লোজুরে রিচ হিকি দ্বারা দুর্দান্ত কাজের জন্য আপনি আগ্রহী হতে পারেন ।
পয়েন্টি

3
@vsync আপনি যে কোনও উপাদান দিয়ে এড়িয়ে যেতে পারবেন না .map()। আপনি তবে .reduce()পরিবর্তে ব্যবহার করতে পারেন , তাই আমি এটি যুক্ত করব।
পয়েন্টি

25

আমি মনে করি অ্যারে থেকে কিছু উপাদান এড়িয়ে যাওয়ার সবচেয়ে সহজ উপায় হ'ল ফিল্টার () পদ্ধতি ব্যবহার করে ।

এই পদ্ধতিটি ( ES5 ) এবং ES6 সিনট্যাক্স ব্যবহার করে আপনি আপনার কোডটি একটি লাইনে লিখতে পারেন এবং এটি যা চান তা ফিরে আসবে :

let images = [{src: 'img.png'}, {src: 'j1.json'}, {src: 'img.png'}, {src: 'j2.json'}];

let sources = images.filter(img => img.src.slice(-4) != 'json').map(img => img.src);

console.log(sources);


1
যে ঠিক কি .filter()জন্য তৈরি করা হয়েছিল
avalanche1

2
এটি কি forEachদুটিের পরিবর্তে একটি পাসে ভাল এবং সম্পূর্ণ করা?
উলিওং

1
আপনার পছন্দ হিসাবে @ ওলিওং তবে দয়া করে এটি বিবেচনায় রাখুন যে এটি এখনও O(n)জটিলতা পরিমাপের মধ্যে থাকবে এবং দয়া করে কমপক্ষে এই দুটি নিবন্ধটিও দেখুন: ফ্রন্টএন্ডকোলিজেনব্লগ. com/ জাভাস্ক্রিপ্ট / ৫ / পি / ৮ / ১৫ / and এবং কোডারওয়াল.com/p/kvzbpa/don-t- পরিবর্তে-জন্য-অ্যারে-ফোরচ-ব্যবহার করুন সব সেরা!
সিংহুমিলিকো

1
ধন্যবাদ @ সিংহুমিলিকো! ঠিক তার কারণেই, আমি এখানে আছি (এবং সম্ভবত আরও অনেকে)। প্রশ্নটি সম্ভবত একবার পুনরাবৃত্তি করে কীভাবে। ফিল্টার এবং .map একত্রিত করা যায় is
জ্যাক ব্ল্যাক

21

2019 সাল থেকে, অ্যারে.প্রোটোটাইপ.ফ্ল্যাটম্যাপ একটি ভাল বিকল্প।

images.flatMap(({src}) => src.endsWith('.json') ? [] : src);

এমডিএন থেকে :

flatMapকোনও মানচিত্রের সময় আইটেমগুলি যুক্ত করতে এবং সরিয়ে দেওয়ার (আইটেমের সংখ্যা সংশোধন করার) উপায় হিসাবে ব্যবহার করা যেতে পারে। অন্য কথায়, এটি আপনাকে সর্বদা এক-একের পরিবর্তে অনেক আইটেমকে (প্রতিটি ইনপুট আইটেমটি পৃথকভাবে পরিচালনা করে) ম্যাপ করার অনুমতি দেয়। এই অর্থে, এটি ফিল্টারটির বিপরীতে কাজ করে। আইটেমটি রাখার জন্য কেবল 1-উপাদান অ্যারে, আইটেমগুলি যুক্ত করতে একাধিক-উপাদান অ্যারে বা আইটেমটি সরাতে 0-উপাদান অ্যারেটি ফিরিয়ে দিন।



1
এটি সত্যই উত্তর, যথেষ্ট সহজ এবং শক্ত। আমরা ফিল্টার এবং হ্রাস চেয়ে ভাল এটি শিখতে।
২ca

19

টিএলডিআর: আপনি প্রথমে আপনার অ্যারে ফিল্টার করতে পারেন এবং তারপরে আপনার মানচিত্রটি সম্পাদন করতে পারেন তবে এটিতে অ্যারেতে দুটি পাসের প্রয়োজন হবে (ফিল্টারটি মানচিত্রে একটি অ্যারে প্রদান করে)। যেহেতু এই অ্যারেটি ছোট, এটি একটি খুব ছোট পারফরম্যান্স ব্যয়। আপনি একটি সাধারণ হ্রাসও করতে পারেন। তবে আপনি যদি অ্যারে (বা যে কোনও ডেটাটাইপ) এর একক পাস দিয়ে এটি কীভাবে করা যায় তা পুনরায় কল্পনা করতে চান, আপনি রিচ হিকি দ্বারা জনপ্রিয় "ট্রান্সডুসার্স" নামে একটি ধারণা ব্যবহার করতে পারেন।

উত্তর:

আমাদের অ্যারেতে ক্রমবর্ধমান ডট চেইনিং এবং অপারেটিংয়ের প্রয়োজন হবে না [].map(fn1).filter(f2)...কারণ এই পদ্ধতির প্রতিটি reducingফাংশনে মেমরির মধ্যবর্তী অ্যারে তৈরি করে ।

সর্বোত্তম পদ্ধতির প্রকৃত হ্রাসকরণ ক্রিয়াকলাপ পরিচালনা করে তাই কেবলমাত্র এক পাসের ডেটা এবং কোনও অতিরিক্ত অ্যারে নেই।

হ্রাসকরণ ফাংশনটি হ'ল ফাংশনটি passedুকে পড়ে reduceএবং উত্স থেকে একটি সঞ্চালক এবং ইনপুট নেয় এবং এমন কিছু ফেরত দেয় যা সংযোজকের মতো দেখায়

// 1. create a concat reducing function that can be passed into `reduce`
const concat = (acc, input) => acc.concat([input])

// note that [1,2,3].reduce(concat, []) would return [1,2,3]

// transforming your reducing function by mapping
// 2. create a generic mapping function that can take a reducing function and return another reducing function
const mapping = (changeInput) => (reducing) => (acc, input) => reducing(acc, changeInput(input))

// 3. create your map function that operates on an input
const getSrc = (x) => x.src
const mappingSrc = mapping(getSrc)

// 4. now we can use our `mapSrc` function to transform our original function `concat` to get another reducing function
const inputSources = [{src:'one.html'}, {src:'two.txt'}, {src:'three.json'}]
inputSources.reduce(mappingSrc(concat), [])
// -> ['one.html', 'two.txt', 'three.json']

// remember this is really essentially just
// inputSources.reduce((acc, x) => acc.concat([x.src]), [])


// transforming your reducing function by filtering
// 5. create a generic filtering function that can take a reducing function and return another reducing function
const filtering = (predicate) => (reducing) => (acc, input) => (predicate(input) ? reducing(acc, input): acc)

// 6. create your filter function that operate on an input
const filterJsonAndLoad = (img) => {
  console.log(img)
  if(img.src.split('.').pop() === 'json') {
    // game.loadSprite(...);
    return false;
  } else {
    return true;
  }
}
const filteringJson = filtering(filterJsonAndLoad)

// 7. notice the type of input and output of these functions
// concat is a reducing function,
// mapSrc transforms and returns a reducing function
// filterJsonAndLoad transforms and returns a reducing function
// these functions that transform reducing functions are "transducers", termed by Rich Hickey
// source: http://clojure.com/blog/2012/05/15/anatomy-of-reducer.html
// we can pass this all into reduce! and without any intermediate arrays

const sources = inputSources.reduce(filteringJson(mappingSrc(concat)), []);
// [ 'one.html', 'two.txt' ]

// ==================================
// 8. BONUS: compose all the functions
// You can decide to create a composing function which takes an infinite number of transducers to
// operate on your reducing function to compose a computed accumulator without ever creating that
// intermediate array
const composeAll = (...args) => (x) => {
  const fns = args
  var i = fns.length
  while (i--) {
    x = fns[i].call(this, x);
  }
  return x
}

const doABunchOfStuff = composeAll(
    filtering((x) => x.src.split('.').pop() !== 'json'),
    mapping((x) => x.src),
    mapping((x) => x.toUpperCase()),
    mapping((x) => x + '!!!')
)

const sources2 = inputSources.reduce(doABunchOfStuff(concat), [])
// ['ONE.HTML!!!', 'TWO.TXT!!!']

সংস্থানসমূহ: সমৃদ্ধ হিক্কি ট্রান্সডুসার্স পোস্ট


16

এখানে একটি মজাদার সমাধান:

/**
 * Filter-map. Like map, but skips undefined values.
 *
 * @param callback
 */
function fmap(callback) {
    return this.reduce((accum, ...args) => {
        let x = callback(...args);
        if(x !== undefined) {
            accum.push(x);
        }
        return accum;
    }, []);
}

বাইন্ড অপারেটরের সাথে ব্যবহার করুন :

[1,2,-1,3]::fmap(x => x > 0 ? x * 2 : undefined); // [2,4,6]

1
এই পদ্ধতিটি আমাকে পৃথক map, filterএবং concatকলগুলি ব্যবহার করা থেকে রক্ষা করেছিল ।
লজিক্যালব্র্যাঞ্চ

11

উত্তরগুলি অতিমাত্রায় প্রান্তের কেসগুলির উত্তর দিন:

const thingsWithoutNulls = things.reduce((acc, thing) => {
  if (thing !== null) {
    acc.push(thing);
  }
  return acc;
}, [])

10

কেন শুধু একটি ফর লুপ ব্যবহার করবেন না?

let arr = ['a', 'b', 'c', 'd', 'e'];
let filtered = [];

arr.forEach(x => {
  if (!x.includes('b')) filtered.push(x);
});

console.log(filtered)   // filtered === ['a','c','d','e'];

বা এমনকি সহজ ব্যবহার ফিল্টার:

const arr = ['a', 'b', 'c', 'd', 'e'];
const filtered = arr.filter(x => !x.includes('b')); // ['a','c','d','e'];

1
সেরা এমন লুপের জন্য সহজ হবে যা ফিল্টার করে এবং একটি নতুন অ্যারে তৈরি করে, তবে ব্যবহারের প্রেক্ষাপটের জন্য mapএটি এখনকার মতো রাখতে দেয়। (4 বছর আগে আমি এই প্রশ্নটি জিজ্ঞাসা করেছি, যখন আমি কোডিং সম্পর্কে কিছুই জানতাম না)
ইসমাইল

উপরের দিকে সরাসরি মানচিত্রের কোনও সরাসরি পথ নেই এবং সমস্ত সমাধান একটি বিকল্প পদ্ধতি ব্যবহার করেছে বলে আমি ভেবেছি যথেষ্ট, আমি একই পদ্ধতিতে ভাবতে পারি এমন সহজ সরল উপায়ে চিপ করব।
অ্যালেক্স

8
var sources = images.map(function (img) {
    if(img.src.split('.').pop() === "json"){ // if extension is .json
        return null; // skip
    }
    else{
        return img.src;
    }
}).filter(Boolean);

.filter(Boolean)একটি প্রদত্ত অ্যারের, যা আপনার ক্ষেত্রে হয় যে কোন falsey মান আউট ফিল্টার করবে null


3

এখানে একটি ইউটিলিটি পদ্ধতি (ES5 সামঞ্জস্যপূর্ণ) রয়েছে যা কেবলমাত্র নাল মানকে মানচিত্র করে (হ্রাস করার জন্য কলটি আড়াল করে):

function mapNonNull(arr, cb) {
    return arr.reduce(function (accumulator, value, index, arr) {
        var result = cb.call(null, value, index, arr);
        if (result != null) {
            accumulator.push(result);
        }

        return accumulator;
    }, []);
}

var result = mapNonNull(["a", "b", "c"], function (value) {
    return value === "b" ? null : value; // exclude "b"
});

console.log(result); // ["a", "c"]


1

আমি .forEachপুনরাবৃত্তি করতে ব্যবহার করি , এবং ফলাফলটি resultsঅ্যারের দিকে ধাক্কা দিয়ে এটি ব্যবহার করি, এই সমাধানের সাহায্যে আমি অ্যারে দিয়ে দু'বার লুপ করব না will


1

ফেলিক্স ক্লিংয়ের মন্তব্যে এক্সট্রোপোলেট করার জন্য আপনি এটি ব্যবহার করতে পারেন .filter():

var sources = images.map(function (img) {
  if(img.src.split('.').pop() === "json") { // if extension is .json
    return null; // skip
  } else {
    return img.src;
  }
}).filter(Boolean);

এটি দ্বারা ফিরে আসা অ্যারে থেকে মিথ্যা মানগুলি সরিয়ে ফেলবে .map()

আপনি এটিকে আরও সহজ করে তুলতে পারেন:

var sources = images.map(function (img) {
  if(img.src.split('.').pop() !== "json") { // if extension is .json
    return img.src;
  }
}).filter(Boolean);

অথবা তীর ফাংশন, অবজেক্ট ডেস্ট্রাকচারিং এবং &&অপারেটর ব্যবহার করে ওয়ান-লাইনার হিসাবেও :

var sources = images.map(({ src }) => src.split('.').pop() !== "json" && src).filter(Boolean);

0

এখানে @theprtk দ্বারা সরবরাহিত কোডটির একটি আপডেট সংস্করণ । উদাহরণস্বরূপ জেনারালাইজড সংস্করণটি দেখানোর জন্য এটি একটু সাফ করা।

দ্রষ্টব্য: আমি এটিকে তাঁর পোস্টে মন্তব্য হিসাবে যুক্ত করব তবে এখনও আমার যথেষ্ট খ্যাতি নেই

/**
 * @see http://clojure.com/blog/2012/05/15/anatomy-of-reducer.html
 * @description functions that transform reducing functions
 */
const transduce = {
  /** a generic map() that can take a reducing() & return another reducing() */
  map: changeInput => reducing => (acc, input) =>
    reducing(acc, changeInput(input)),
  /** a generic filter() that can take a reducing() & return */
  filter: predicate => reducing => (acc, input) =>
    predicate(input) ? reducing(acc, input) : acc,
  /**
   * a composing() that can take an infinite # transducers to operate on
   *  reducing functions to compose a computed accumulator without ever creating
   *  that intermediate array
   */
  compose: (...args) => x => {
    const fns = args;
    var i = fns.length;
    while (i--) x = fns[i].call(this, x);
    return x;
  },
};

const example = {
  data: [{ src: 'file.html' }, { src: 'file.txt' }, { src: 'file.json' }],
  /** note: `[1,2,3].reduce(concat, [])` -> `[1,2,3]` */
  concat: (acc, input) => acc.concat([input]),
  getSrc: x => x.src,
  filterJson: x => x.src.split('.').pop() !== 'json',
};

/** step 1: create a reducing() that can be passed into `reduce` */
const reduceFn = example.concat;
/** step 2: transforming your reducing function by mapping */
const mapFn = transduce.map(example.getSrc);
/** step 3: create your filter() that operates on an input */
const filterFn = transduce.filter(example.filterJson);
/** step 4: aggregate your transformations */
const composeFn = transduce.compose(
  filterFn,
  mapFn,
  transduce.map(x => x.toUpperCase() + '!'), // new mapping()
);

/**
 * Expected example output
 *  Note: each is wrapped in `example.data.reduce(x, [])`
 *  1: ['file.html', 'file.txt', 'file.json']
 *  2:  ['file.html', 'file.txt']
 *  3: ['FILE.HTML!', 'FILE.TXT!']
 */
const exampleFns = {
  transducers: [
    mapFn(reduceFn),
    filterFn(mapFn(reduceFn)),
    composeFn(reduceFn),
  ],
  raw: [
    (acc, x) => acc.concat([x.src]),
    (acc, x) => acc.concat(x.src.split('.').pop() !== 'json' ? [x.src] : []),
    (acc, x) => acc.concat(x.src.split('.').pop() !== 'json' ? [x.src.toUpperCase() + '!'] : []),
  ],
};
const execExample = (currentValue, index) =>
  console.log('Example ' + index, example.data.reduce(currentValue, []));

exampleFns.raw.forEach(execExample);
exampleFns.transducers.forEach(execExample);

0

আপনি আপনার পদ্ধতি পরে ব্যবহার করতে পারেন map()filter()আপনার ক্ষেত্রে উদাহরণের জন্য পদ্ধতি :

var sources = images.map(function (img) {
  if(img.src.split('.').pop() === "json"){ // if extension is .json
    return null; // skip
  }
  else {
    return img.src;
  }
});

পদ্ধতি ফিল্টার:

const sourceFiltered = sources.filter(item => item)

তারপরে, কেবল বিদ্যমান আইটেমগুলি নতুন অ্যারেতে রয়েছে sourceFiltered

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