12 Şubat 2019 Salı

Array map metodu

Giriş
Açıklaması şöyle
The map() method is used to apply a function on every element in an array and then return a new array.
Array'deki her elemanı bir metoda sokar ve sonuçları dizi olarak döner. Eğer yeni bir dizi istemiyorsak map() yerine forEach() metodu da kullanılabilir.

Bounding Scope
map() metodunu her zaman arrow function ile kullanmak daha iyi. Şöyle yaparız. Böylece arrow function içinde this.XYZ şeklinde değişkenleri kullanabiliriz.
this.props.answeredQuestions.map( (question, index) => {
//rest of the code
});
Ancak şöyle yaparsak bu kod çalışmaz.
this.props.answeredQuestions.map(function(question, index) {
  if (!this.state.viewMoreToken) {
    ...
  }
});
Şu hatayı alırız.
TypeError: Cannot read property 'state' of undefined
Bir diğer çözüm ise this kullanmadan değişkenler erişmek. Şöyle yaparız.
render() {
  const { answeredQuestions } = this.props;
  const { viewMoreToken } = this.state;
  
  return (
    {answeredQuestions &&
     answeredQuestions.map(function(question, index) {
     if (!viewMoreToken) {...}
     }
    }
);
Java İle Farkı
Açıklaması şöyle. Eğer arka arkaya bağlanmış map() çağrıları varsa Java ilk elemanı alır birinci map() işlemine sokar daha sonra ikinci map() işlemine sokar.
.map will necessarily iterate through the whole input array before resolving to the mapped output array (after which the mapped output array will then have another .map called on it).
Elimizde şöyle bir kod olsun.
List<Integer> nums = Arrays.asList(1,2,3,4,5,6);    
nums.stream().map(x->{
    x = x * x;
    System.out.println("map1="+x);
    return x;
}).map(x->{
    x = x * 3;
    System.out.println("map2="+x);
    return x;
}).forEach(x-> System.out.println("forEach="+x));
Çıktı olarak şunu alırız. Burada ilk map işlemi çalıştırılıyor ve birinci eleman olan 1 değerinin önce karesi alınıyor. Daha sonra sonuç ikinci map() işlemine geçiliyor ve  kare değeri 3 ile çarpılıyor.
map1=1
map2=3
forEach=3
map1=4
map2=12
forEach=12
map1=9
map2=27
forEach=27
map1=16
map2=48
forEach=48
map1=25
map2=75
forEach=75
map1=36
map2=108
forEach=108
Javascript'te ise map tüm diziyi dolaşır. Elimizde şöyle bir kod olsun.
var nums = [1,2,3,4,5,6 ];
nums.map(x => {
  x = (x * x);
  console.log('map1='+x);
  return x;})
.map(x => {
  x = x * 3;
  console.log('map2='+x);
  return x;})
.forEach(x=> console.log('forEach='+x));
Çıktı olarak şunu alırız. Önce 1,2,3.. değerlerinin karesi alınıyor daha sonra bu değerler 3 ile çarpılıyor.
map1=1
 map1=4
 map1=9
 map1=16
 map1=25
 map1=36
 map2=3
 map2=12
 map2=27
 map2=48
 map2=75
 map2=108
 forEach=3
 forEach=12
 forEach=27
 forEach=48
 forEach=75
 forEach=108
Örnek
Array map metodu yeni bir dizi döner. a,b,c karakterlerini içeren diziyi map metoduna sokuyoruz.
var namelist = ['a', 'b', 'c'];
var set =namelist.map(function(e) { return {name: e, p1: '', p2: '' }});
Sonuç olarak yeni bir nesne dizisi dönüyoruz.
var set = [{
  name: 'a',
  p1: '',
  p2: '',
},
{
  name: 'b',
  p1: '',
  p2: '',
},
{
  name: 'c',
  p1: '',
  p2: '',
}];
Örnek
Dizideki her bir string'e önek vermek istersek şöyle yaparız.
var arr = ['a','b','c'];
var prefix = 'prefix_';

var newArr = arr.map(el => prefix + el);
console.log(newArr);
Örnek
Eğer elimizde veri primitive tip ise zaten ilk diziyi değiştirmenin yolu yok. Şöyle yaparız.
// testing mutations with Array methods
function ageUp (n){
  return n+1;
}

// map does not mutate original
d = [11,12,13,14,15]
console.log("array d before map...", d)
const newd = d.map(
  num => {
    num = ageUp(num)
    return num
  }
)
console.log("array d after map ...", d)
console.log("newd array after...", newd)

// array d before map... [ 11, 12, 13, 14, 15 ]
// array d after map ... [ 11, 12, 13, 14, 15 ]
// newd array after... [ 12, 13, 14, 15, 16 ]
Ancak elimizdeki veri object ise ilk dizideki değerler de değişebilir. Şöyle yaparız.
// testing mutations with Array methods
function ageUp (n){
  return n+1;
}
function coolName (name){
  return name+name;
}

const b = [{ name: "Jonas", age: 20}, { name: "Jana", age: 30}]


// map, here, also mutates original...
console.log("array before map...", b)
const newb = b.map(
  person => {
  person.name = coolName(person.name)
  person.age = ageUp(person.age)
  return person
}
)
console.log("array after map...", b)
console.log("array newb...", newb)

// array before map... [ { name: 'Jonas', age: 20 }, { name: 'Jana', age: 30 } ]    
// array after map... [ { name: 'JonasJonas', age: 21 }, { name: 'JanaJana', age: 31 } ]
// array newb... [ { name: 'JonasJonas', age: 21 }, { name: 'JanaJana', age: 31 } ]
Örnek
Elimizdeli object'i değiştirince ilk dizinin de değiştiğini görmek için şöyle yaparız.
function point(x,y){
  return {x,y}
}

arr1 = [point(1,2), point(3,4)];
console.log(arr1, "arr1");

arr2 = arr1.map(b=>{
  b.x = b.x+2;
  b.y = b.y+2;
  return b;
})
console.log(arr1, "arr1");
console.log(arr2, "arr2");
Eğer yeni bir object dönmek istersek şöyle yaparız.
arr2 = arr1.map(b => {
  return {
    x: b.x + 2,
    y: b.y + 2
  };
})
veya şöyle yaparız.
const arr2 = arr1.map(({x, y}) => ({
  x: x + 2,
  y: y + 2
}))
Örnek
Açıklaması şöyle.
... callback is invoked only for indexes of the array which have assigned values, including undefined.
map metodu sadece dolu elemanlar için çalışır. Elimizde length'i olan ancak içi boş bir dizi olsun
Array(2); // [empty × 2] 
Şöyle yaparız ve yine boş bir dizi alırız.
Array(2).map( () => "foo");  // [empty × 2]