2013-09-26 87 views
103

Chức năng map trong underscore.js, nếu được gọi với đối tượng javascript, trả về một mảng các giá trị được ánh xạ từ các giá trị của đối tượng.Bản đồ trên các phím bảo vệ đối tượng

_.map({one: 1, two: 2, three: 3}, function(num, key){ return num * 3; }); 
=> [3, 6, 9] 

có cách nào để bảo vệ khóa không? tức là, tôi muốn một hàm trả về

{one: 3, two: 6, three: 9} 
+0

Nếu bạn, như tôi, đến đây tìm kiếm một chức năng 'mapValues' thay đổi đối tượng thực tế thay vì trả về một đối tượng mới, hãy kiểm tra giải pháp đơn giản này: http: // stackoverflow. com/questions/30894044/destructively-map-object-properties-function –

Trả lời

178

Với gạch

gạch cung cấp một chức năng _.mapObject để ánh xạ các giá trị và giữ gìn các phím.

_.mapObject({ one: 1, two: 2, three: 3 }, function (v) { return v * 3; }); 

// => { one: 3, two: 6, three: 9 } 

DEMO


Với Lodash

Lodash cung cấp một chức năng _.mapValues để ánh xạ các giá trị và giữ gìn các phím.

_.mapValues({ one: 1, two: 2, three: 3 }, function (v) { return v * 3; }); 

// => { one: 3, two: 6, three: 9 } 

DEMO

+0

cảm ơn! Tôi thấy chức năng đó và nghĩ về thứ gì đó như thế này, nhưng tôi đã tự hỏi liệu có cách nào trực tiếp hơn để lập bản đồ đối tượng không. – xuanji

+0

Đã có những nỗ lực để có được một _.mapValues ​​chức năng thành gạch dưới: [Relevant Issue] (https://github.com/jashkenas/underscore/issues/220), [Pull Request for _.mapValues] (https://github.com/jashkenas/underscore/pull/ 1953). Tôi hy vọng điều này đi qua :) – raffomania

+0

có vẻ như tôi đang khiến OBJECT trở thành một đối tượng, hay tôi không nghĩ ra? – jsh

3

_.map trả về một mảng chứ không phải đối tượng.

Nếu bạn muốn một đối tượng tốt hơn bạn nên sử dụng một chức năng khác, chẳng hạn như each; nếu bạn thực sự muốn sử dụng bản đồ bạn có thể làm một cái gì đó như thế này:

Object.keys(object).map(function(value, index) { 
    object[value] *= 3; 
}) 

nhưng đó là khó hiểu, khi nhìn thấy map người ta sẽ mong đợi để có một mảng kết quả và sau đó làm một cái gì đó với nó.

+0

Tôi đã có một cảm giác đọc các tài liệu mà nó sẽ không được tự nhiên để thử điều này trong underscore.js. Tôi nghĩ rằng trường hợp sử dụng của tôi là khá tự nhiên, tại sao họ không hỗ trợ nó? – xuanji

+0

Một lý do có thể là 'map' được sử dụng để thay đổi đầu vào tạo ra một mảng làm đầu ra, bạn có thể soạn' _.object' và '_.map' thành @GG. đã viết, nhưng đó là một vấn đề của hương vị vào thời điểm này. –

2

Tôi nghĩ rằng bạn muốn có một chức năng mapValues (để ánh xạ một chức năng so với giá trị của một đối tượng), đó là dễ dàng, đủ để thực hiện bản thân:

mapValues = function(obj, f) { 
    var k, result, v; 
    result = {}; 
    for (k in obj) { 
    v = obj[k]; 
    result[k] = f(v); 
    } 
    return result; 
}; 
52

Tôi quản lý để tìm các chức năng cần thiết trong lodash, một thư viện tiện ích tương tự như gạch dưới.

http://lodash.com/docs#mapValues

_.mapValues(object, [callback=identity], [thisArg]) 

Tạo một đối tượng với các phím tương tự như đối tượng và các giá trị được tạo ra bởi chạy từng sở hữu tài sản đếm được của đối tượng thông qua việc gọi lại. Gọi lại bị ràng buộc với thisArg và được gọi với ba đối số; (giá trị, khóa, đối tượng).

17

var mapped = _.reduce({ one: 1, two: 2, three: 3 }, function(obj, val, key) { 
 
    obj[key] = val*3; 
 
    return obj; 
 
}, {}); 
 

 
console.log(mapped);
<script src="http://underscorejs.org/underscore-min.js"></script> 
 
<script src="https://getfirebug.com/firebug-lite-debug.js"></script>

1

Một sửa chữa hỗn hợp cho bản đồ gạch lỗi: P

_.mixin({ 
    mapobj : function(obj, iteratee, context) { 
     if (obj == null) return []; 
     iteratee = _.iteratee(iteratee, context); 
     var keys = obj.length !== +obj.length && _.keys(obj), 
      length = (keys || obj).length, 
      results = {}, 
      currentKey; 
     for (var index = 0; index < length; index++) { 
      currentKey = keys ? keys[index] : index; 
      results[currentKey] = iteratee(obj[currentKey], currentKey, obj); 
     } 
     if (_.isObject(obj)) { 
      return _.object(results) ; 
     } 
     return results; 
    } 
}); 

Một cách giải quyết đơn giản mà giữ quyền chủ chốt và trở lại như đối tượng Nó vẫn được sử dụng theo cách tương tự như tôi khách, bạn có thể sử dụng chức năng này để ghi đè lên các chức năng bugy _.map

hoặc đơn giản là tôi sử dụng nó như là một mixin

_.mapobj (options , function(val, key, list) 
13

Tôi biết điều này là cũ, nhưng bây giờ gạch có một bản đồ mới cho các đối tượng:

_.mapObject(object, iteratee, [context]) 

Bạn có thể dĩ nhiên xây dựng một bản đồ linh hoạt cho cả hai mảng và các đối tượng

_.fmap = function(arrayOrObject, fn, context){ 
    if(this.isArray(arrayOrObject)) 
     return _.map(arrayOrObject, fn, context); 
    else 
     return _.mapObject(arrayOrObject, fn, context); 
} 
+4

Lưu ý đối với người dùng lodash: jdalton đã quyết định [ngắt khả năng tương thích với underscore.js] (https://github.com/lodash/lodash/issues/980) về thay đổi này. lodash sẽ không hỗ trợ 'mapObject'; nhìn vào phương thức 'mapValues' của lodash thay vào đó. –

7

Làm thế nào abo ut phiên bản này trong JS đơn giản (ES6/ES2015)?

let newObj = Object.assign(...Object.keys(obj).map(k => ({[k]: obj[k] * 3}))); 

jsbin

Nếu bạn muốn ánh xạ trên một đối tượng đệ quy (bản đồ obj lồng nhau), nó có thể được thực hiện như thế này:

const mapObjRecursive = (obj) => { 
    Object.keys(obj).forEach(key => { 
    if (typeof obj[key] === 'object') obj[key] = mapObjRecursive(obj[key]); 
    else obj[key] = obj[key] * 3; 
    }); 
    return obj; 
}; 

jsbin

Kể từ ES7/ES2016 bạn có thể sử dụng Object.entries thay vì Object.keys như thế này:

let newObj = Object.assign(...Object.entries(obj).map([k, v] => ({[k]: v * 3}))); 
0

Tôi biết nó được một thời gian dài, nhưng vẫn là giải pháp rõ ràng nhất qua lần (aka giảm trong js) là mất tích, vì lợi ích của sự hoàn chỉnh, tôi sẽ giới để nó ở đây:

function mapO(f, o) { 
    return Object.keys(o).reduce((acc, key) => { 
    acc[key] = f(o[key]) 
    return acc 
    }, {}) 
}