We've seen how we can transduce from arrays or other iterables, but plain objects aren't iterable in Javascript. In this lesson we'll modify our transduce() function so that it supports iterating from plain objects as well, treating each key value pair as an entry in the collection.

To do this we'll be using a lodash function called entries.

The whole point to make collection works for Object type is because when we use for.. of loop, Object is not itertable type, so Object still cannot be used. The fix that problem, we can use 'entries' from lodash, to only get value as an array from the Object, so that we can loop though the array.

import {isPlainObject, entries} from 'lodash';
import {map, into} from '../utils'; let transduce = (xf /** could be composed **/, reducer, seed, _collection) => { const transformedReducer = xf(reducer);
let accumulation = seed; const collection = isPlainObject(_collection) ? entries(_collection) : _collection; for (let value of collection) {
accumulation = transformedReducer(accumulation, value);
} return accumulation;
}; const objectValues = obj => {
return into([], map(kv => kv[1]), obj);
}; objectValues({one: 1, two: 2});

---

const { isObject, isArray } = require('crocks');
const { toPairs } = require('ramda'); const data = [,,];
const inc = x => x + ;
const double = x => * x;
const lessThanThree = x => x < ;
const toUpper = s => s.toUpperCase();
const isVowel = char => ['a', 'e', 'i', 'o', 'u'].includes(char.toLowerCase());
const compose = (...fns) => (...args) => fns.reduce((acc, fn) => [fn.call(null, ...acc)], args)[]
////////////////////
/**
* Problem: We loop over array 3 times! We want to loop over only once
* in order to improve the profermance.
*/
const res1 = data
.filter(lessThanThree)
.map(double)
.map(inc) console.log(res1) // [3,5] ////////////////////////////////
/**
* Problem: it is not pure function and we do mutation. But it is faster
* than we do .filter.map.map style, because it only loop the array once.
*/
let res2 = [];
data.forEach((x) => {
let item;
if (lessThanThree(x)) {
item = inc(double(x))
res2.push(item);
}
})
console.log(res2) // [3,5] ////////////////////////////////
/**
* Good: We avoid the mutation and can be write as pure function and it only loop once!
* Problem: But we lose our function composion style! We still want .filter.map.map styling.
* Meanwhile it should be profermance wise.
*/
const res3 = data.reduce((acc, curr) => {
if (lessThanThree(curr)) {
acc.push(inc(double(curr)));
}
return acc;
}, []);
console.log(res3); // [3,5] ////////////////////////////////////
//data.reduce(reducer, seed), reducer is something we can compose!
//Because reducer :: (acc, curr) => acc
//For every reducer functions' signature are the same.
//If the function sinature are the same, then we can compose function together!
const _mapReducer = (xf, array) =>
array.reduce((acc, curr) => {
acc.push(xf(curr))
return acc;
}, []);
const _filterReducer = (xf, array) =>
array.reduce((acc, curr) => {
if (xf(curr)) acc.push(curr);
return acc;
}, []);
// To make fns easy to compose, we extract 'array' data & init value
const mapReducer = (xf) => ((acc, curr) => {
acc.push(xf(curr))
return acc;
});
const filterReducer = pred => ((acc, curr) => {
if (pred(curr)) acc.push(curr);
return acc;
});
// now mapReducer and filterReducer both have the same function signature.
console.log(data.reduce(mapReducer(double), [])); // [2,4,6]
console.log(data.reduce(mapReducer(inc), [])); // [2,3,4]
console.log(data.reduce(filterReducer(lessThanThree), [])); // [1,2] // In order to compose reudcers together we need to make mapReducer and filterReducer as high order functions to take reducer as arguement
// Take a reducer as input and return a reducer signature as output is the key to do composion!
const map = xf => reducer => ((acc, curr) => {
acc = reducer(acc, xf(curr))
return acc;
});
const filter = pred => reducer => ((acc, curr)=> {
if (pred(curr)) acc = reducer(acc, curr)
return acc;
})
// For mapReducer and filterReducer, we both do acc.push()
// therefore we can extrat this as base reducer
const pushReducer = (acc, value) => {
acc.push(value);
return acc;
}; /**
* Now we are able to use functional style and loop the array only once!s
*/
const doulbeLessThanThree = compose(
map(inc),
map(double),
filter(lessThanThree)
)
const res5 = data.reduce(doulbeLessThanThree(pushReducer), []);
console.log(res5); // [3,5] ////////////////////////////////////
// Define our transducer!
/**
* transducer :: ((a -> b -> a), (a -> b -> a), [a], [a]) -> [a]
* @param {*} xf: base reducer
* @param {*} reducer: the composion redcuer signature
* @param {*} seed : init value
* @param {*} collection : data
*/
const _transducer = (xf, reducer, seed, collection) => {
return collection.reduce(xf(reducer), seed);
}
const res6 = _transducer(doulbeLessThanThree, pushReducer, [], data);
console.log(res6); // [3,5] const transducer = (xf, reducer, seed, collection) => {
let acc = seed; collection = isObject(collection) ? toPairs(collection): collection const transformReducer = xf(reducer);
for (let curr of collection) {
acc = transformReducer(acc, curr)
} return acc;
} const res7 = transducer(
compose(filter(isVowel), map(toUpper)),
(acc, curr) => acc + curr,
'',
'transducer'
);
console.log("", res7); // AUE const numMap = new Map()
numMap.set('a', );
numMap.set('b', );
numMap.set('c', );
numMap.set('d', );
const res8 = transducer(
doulbeLessThanThree,
pushReducer,
[],
numMap.values()
);
console.log("", res8); // [3,5] /**
* into helper
* transducer = (xf, reducer, seed, colllection)
* Until so far, we have to know what kind of base reducer we need to use
* for example, push reduer for array, concat reducer for string...
*
* The idea of into helper is to let transducer to figure out what reducer
* we want to use automaticlly instead of we telling transducer which one to use
*
* into:: (to, xf, collection)
*/ const objectReducer = (obj, value) => Object.assign(obj, value);
const into = (to, xf, collection) => {
if (Array.isArray(to)) {
return transducer(xf, pushReducer, to, collection);
} else if (isObject(to)) {
return transducer(xf, objectReducer, to, collection)
}
throw new Error('into only supports arrays and objects as `to`');
} /**
* seq helper
* Different from into help, seq helper will infer the collection type
*/
const seq = (xf, collection) => {
if (isArray(collection)) {
return transducer(xf, pushReducer, [], collection);
} else if (isObject(collection)) {
return transducer(xf, objectReducer, {}, collection)
}
throw new Error('seq : unsupport collection type');
}
console.log(seq(compose(
filter(x => x < ),
map(x => x * )
), [,,])); const filp = map(([k, v]) => ({[v]: k}));
console.log(seq(filp, {one: , two: })); /**{1: 'one, 2: 'two'} */

[Transducer] Make Transducer works for Iteratable collection and Object的更多相关文章

  1. [Javascript] Transduce over any Iteratable Collection

    So far we've been transducing by manually calling .reduce() on arrays, but we want to be able to tra ...

  2. Scalaz(48)- scalaz-stream: 深入了解-Transducer: Process1-tee-wye

    在上一篇讨论里我们介绍了Source,它的类型款式是这样的:Process[F[_],O].Source是通过await函数来产生数据流.await函数款式如下: def await[F[_], A, ...

  3. java 深入技术二(Collection)

    1. java集合 存储和管理多个java对象 包括很多java类和接口 Collection List                              Set ArrayList  Lin ...

  4. 设计一个泛型类Collection

    要求:设计一个泛型类Collection,它存储object对象的集合(在数组中),以及该集合当前的大小.提供public方法isEmtpy,makeEmpty,insert,remove,isPre ...

  5. java中集合Collection转list对象

    参考:java中集合Collection转list对象 首先我的需求是获取到购物车列表,购物车列表是一个Map对象,构造方法获取购物项,这里购物项是Collection对象 // 购物项集合,K商品I ...

  6. java collection.frequency方法

    collection.frequency方法,可以统计出某个对象在collection中出现的次数 比如: frequency(Collection<?> c, Object o)     ...

  7. PASCAL VOC数据集The PASCAL Object Recognition Database Collection

    The PASCAL Object Recognition Database Collection News 04-Apr-07: The VOC2007 challenge development ...

  8. Java集合----Collection工具类

    Collections 工具类 Collections 是一个操作 Set.List 和 Map 等集合的工具类 Collections 中提供了大量方法对集合元素进行排序.查询和修改等操作,还提供了 ...

  9. Java基础学习-Collection体系结构和迭代测试

    package Collection; import java.util.ArrayList; import java.util.Collection; import java.util.Iterat ...

随机推荐

  1. hihocoder #1580 : Matrix (DP)

    #1580 : Matrix 时间限制:1000ms 单点时限:1000ms 内存限制:256MB 描述 Once upon a time, there was a little dog YK. On ...

  2. java float与double的范围和精度

    float与double的范围和精度 1. 范围  float和double的范围是由指数的位数来决定的.  float的指数位有8位,而double的指数位有11位,分布如下:  float:  1 ...

  3. iOS 9音频应用播放音频之播放控制暂停停止前进后退的设置

    iOS 9音频应用播放音频之播放控制暂停停止前进后退的设置 ios9音频应用播放控制 在“iOS 9音频应用播放音频之ios9音频基本功能”一文可以看到AVAudioPlayer类有很多的属性以及方法 ...

  4. 2017/11/6 Leetcode 日记

    2017/11/6 Leetcode 日记 344. Reverse String Write a function that takes a string as input and returns ...

  5. PHP 笔记——会话控制

    1. Session的操作 1.1 启动 Session session_start(void):bool 1.2 注册 Session 会话变量启动后,全部被保存在全局数组$_SESSION[]中. ...

  6. 「APIO2018新家」

    「APIO2018新家」 题目描述 五福街是一条笔直的道路,这条道路可以看成一个数轴,街上每个建筑物的坐标都可以用一个整数来表示.小明是一位时光旅行者,他知道在这条街上,在过去现在和未来共有 \(n\ ...

  7. 2017-2018-1 JAVA实验站 冲刺 day03

    2017-2018-1 JAVA实验站 冲刺 day03 各个成员今日完成的任务 小组成员 今日工作 完成进度 张韵琪 写博客.进行工作总结 100% 齐力锋 部分按钮图片.对按钮图片进行ps 100 ...

  8. 2017-2018-1 JAVA实验站 冲刺 day07

    2017-2018-1 JAVA实验站 冲刺 day07 各个成员今日完成的任务 小组成员 今日工作 完成进度 张韵琪 写博客.进行工作总结 100% 齐力锋 部分按钮图片.对按钮图片进行ps 100 ...

  9. Mybatis 删除多条数据XML SQL语句删除

    Mybatis 删除多条数据XML SQL语句删除 1.删除多条数据SQL写法 <delete id="deleteParamsByIds"> delete from ...

  10. Mac 显示隐藏的文件

    要显示隐藏文件: 在终端中输入代码:defaults write com.apple.finder AppleShowAllFiles -bool true 隐藏文件: 在终端输入代码:default ...