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. Maven入门使用(一)

    一.什么是maven 一般认为maven是项目构建工具+依赖管理工具+项目信息管理工具. maven是一个强大的构建工具,能够帮助我们自动化构建过程. 清理.编译.测试.生成报告.打包.部署都是可以通 ...

  2. PHP的数据类型与常量使用

    数据类型之间的相互转换 1.强制转换:setType(变量,类型):这个函数将原变量的类型改变//integer,int,float,double,bool,boolen,string,arry,ob ...

  3. 山东省第四届省赛 E-Mountain Subsequences

    Description Coco is a beautiful ACMer girl living in a very beautiful mountain. There are many trees ...

  4. [BZOJ4554][TJOI2016&&HEOI2016]游戏(匈牙利)

    4554: [Tjoi2016&Heoi2016]游戏 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 857  Solved: 506[Sub ...

  5. MSSQL SELECT(刚刚)新插入到表中的那条记录

    假设对表 TXxxxxxxx 表新插入一条记录,然后要 SELECT 出刚刚插入的这条记录.可使用 SCOPE_IDENEITY(); 处理.具体代码参考如下: INSERT INTO TXxxxxx ...

  6. Swift 笔记1

    // Playground - noun: a place where people can play import Cocoa var str = "Hello, playground&q ...

  7. mySql---logback日志写入数据库(mysql)配置

    如题  建议将日志级别设置为ERROR.这样可以避免存储过多的数据到数据中. 1  logback 配置文件(如下) <?xml version="1.0" encoding ...

  8. JVM堆内存的分代

    虚拟机的堆内存共划分为三个代:年轻代(Young Generation).年老代(Old Generation)和持久代(PermanentGeneration).其中持久代主要存放的是Java类的类 ...

  9. XmlnsDefinitionAttribute Is Pretty Nifty

    When we want to declaratively use our custom controls or reference the types we defined in XAML, we ...

  10. VS2010程序打包操作(超详细的)转

    1.  在vs2010 选择“新建项目”----“其他项目类型”----“Visual Studio Installerà“安装项目”: 命名为:Setup1 . 这是在VS2010中将有三个文件夹, ...