programing

.map()의 요소를 건너뛰는 방법

kingscode 2022. 10. 29. 10:14
반응형

.map()의 요소를 건너뛰는 방법

에서 어레이 요소를 건너뛰려면 어떻게 해야 합니다..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"]

그저..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()콜백이미지 소스는 필터 조작에 의해 유지되었을 경우에만 결과 배열에 푸시됩니다.

update : 이 질문은 많은 주목을 받고 있습니다.다음의 설명을 덧붙이겠습니다.의 목적.map()개념으로서 "맵"이 의미하는 바를 정확히 실행하는 것입니다.즉, 특정 규칙에 따라 값 목록을 다른 값 목록으로 변환합니다.도시 몇 개가 완전히 없어지면 어떤 나라의 종이 지도가 이상하게 보일 수 있듯이, 한 목록에서 다른 목록으로 매핑하는 것은 결과 값 세트가 1:1일 때만 의미가 있습니다.

일부 값을 제외한 오래된 목록에서 새 목록을 만드는 것이 의미가 없다고 말하는 것이 아닙니다.난 그냥 확실히 하려고 하는 거야.map()에는 오래된 값의 변환에 의해 형성된 값만을 사용하여 오래된 배열과 같은 길이의 새 배열을 작성하는 단순한 의도가 있습니다.

2019년부터 Array.protype.platMap은 좋은 옵션입니다.

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

MDN에서:

flatMap는 지도에서 항목을 추가 및 제거하는 방법(항목 수 제한)으로 사용할 수 있습니다.즉, 1대 1이 아닌 (각 입력 항목을 개별적으로 처리하여) 많은 항목을 여러 항목에 매핑할 수 있습니다.그런 의미에서 필터와 반대로 작용합니다.항목을 보관할 1-element 어레이, 항목을 추가할 다중 요소 어레이 또는 항목을 제거할 0-element 어레이를 반환하기만 하면 됩니다.

배열에서 몇 가지 요소를 건너뛰는 가장 간단한 방법은 filter() 메서드를 사용하는 것이라고 생각합니다.

이 메서드(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);

TLDR: 먼저 어레이를 필터링한 후 맵을 실행할 수 있지만, 이 작업을 수행하려면 어레이에 두 번 통과해야 합니다(필터는 매핑할 어레이를 반환합니다).이 어레이는 작기 때문에 퍼포먼스 비용은 매우 낮습니다.단순하게 줄일 수도 있습니다.단, 어레이(또는 임의의 데이터형)를 1회 통과하는 것으로 이것을 실현하는 방법을 재상상화하려면 , Rich Hickey가 개발한 「트랜스듀서」라고 하는 아이디어를 사용할 수 있습니다.

답변:

할 필요는 .[].map(fn1).filter(f2)...에서는, 모든 「에 에,reducing★★★★★★ 。

가장 좋은 방법은 실제 축소 기능으로 작동하기 때문에 데이터 패스는 1개뿐이며 추가 어레이는 없습니다.

는 '감소함수'로입니다.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!!!']

리소스: 리치히키 변환기 포스트

여기 재미있는 해결책이 있습니다.

/**
 * Filter-map. Like map, but skips undefined values.
 *
 * @param callback
 */
function fmap(callback) {
    return this.reduce((accum, ...args) => {
        const 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]

각 루프를 사용하면 어떨까요?

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'];

불필요한 엣지 케이스에 대한 답변:

const thingsWithoutNulls = things.reduce((acc, thing) => {
  if (thing !== null) {
    acc.push(thing);
  }
  return acc;
}, [])
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 값은 "falsey"입니다.★★★★★★★★★★★★★★★★★★·null.

펠릭스 클링의 코멘트를 추정하려면.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);

이 falsey에 의해 됩니다..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);

다음으로 null 이외의 값만 매핑하는 유틸리티 메서드(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행 ES5/ES6에서 늘 또는 정의되지 않은 경우

//will return array of src 
images.filter(p=>!p.src).map(p=>p.src);//p = property


//in your condition
images.filter(p=>p.src.split('.').pop() !== "json").map(p=>p.src);

용 i i i i를 쓴다..forEachresults 후 이에서는 I not over array over array를 사용합니다.

어프터 어프터 어프터 어프터 어프터 어프터 어프터 어프터 어프터 어프터 어프터 어프터 어프터 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.

다음은 @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);

당신은 이걸 할 수 있다.

var sources = [];
images.map(function (img) {
    if(img.src.split('.').pop() !== "json"){ // if extension is not .json
        sources.push(img.src); // just push valid value
    }
});

용 i i i i를 쓴다.foreach():

var sources = [];

images.forEach(function (img) {
    if(img.src.split('.').pop() !== "json"){ // if extension is .json
        sources.push(img);
    }
});

메모: 당신의 논리를 부정했습니다.

다음과 같이 맵 + 필터를 사용할 수 있습니다.

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

const arr = [0, 1, '', undefined, false, 2, undefined, null, , 3, NaN];
const filtered = arr.filter(Boolean);
console.log(filtered);

/*
    Output: [ 1, 2, 3 ]
*/

은 '''를 하는 것입니다.filter+map입력 어레이를 동시에 1회 반복할 수 있습니다.그러기 위해서는 어레이를 (내부적으로는) 반복 가능한 것으로 취급해야 합니다.

아래 답변은 이미지를 처리하기 위해 반복 작업 라이브러리를 사용합니다.

import {pipe, filter, map} from 'iter-ops';

const result = pipe(
    images,
    filter(img => img.src.split('.').pop() !== 'json'),
    map(img => img.src)
);

console.log('result:', [...result]);

추신: 저는 '반복수술'의 전자저자입니다.

언급URL : https://stackoverflow.com/questions/24806772/how-to-skip-over-an-element-in-map

반응형