【译】Immutable.js : 操作 Set -8
不可变集提供了强大的集合操作,如相交,联合和减法。本教程将向您展示如何使用它们,以及何时使用它们来代替合并列表
什么时候使用Sets和Union,Intersect和Subtract方法
Set的独特性质是其值始终是唯一的。不可变的设置方法强制这种唯一性,并会自动防止重复被添加到一个集,而不会引发异常。
当使用三个特定于Set的方法(union,intersect和subtract)时,一个Set真正进入自己的状态。
Set.union()
将两个值的值组合在一起,确保不存在重复。 Union返回Set B的值与Set A的值,删除重复项。它不同于List.merge(),List.merge()覆盖列表A的值与列表B中存在于同一索引处的值。相反,Set.union()结合了两组值。Set.intersect()
提供了两个集合A和B,并返回一个只包含A和B中存在的值的集合。Set.subtract()
需要两个集合A和B,并返回一个只包含A中存在的值但不存在于B中的集合。
How to operate on an Immutable Set
原始值(number,string)
当执行Set操作时(即减法,相交或联合),您需要了解JavaScript如何处理相等性。使用JavaScript原始值(布尔值,数字,字符串,空值和未定义值),等同于您所期望的:例如,2总是等于2,而'string'=== string'。
Working with JavaScript Objects
但是,使用JavaScript对象则是非常不同的。具体而言,一个对象只有等于自己。使用相同的键和值创建两个独立的对象不会使它们相等。
这是因为对象是通过引用(即它们在内存中的位置)进行比较的,而基元是通过值进行比较的。如果两个数字具有相同的值,则认为它们是相等的。然而,具有相同值的两个对象将总是驻留在两个不同的存储器位置,因此不能相等。
const obj1 = { key: 'value' };
const obj2 = { key: 'value' }
// The values assigned obj1 and obj2 reside in two different memory locations.
// They are therefore not equal:
obj1 === obj2;
// OUTPUT
false
为什么这很重要?因为一个集合必须有唯一的值,为了检查重复,它需要知道(你也是这样!)是什么使一个值等于另一个值。在基元的情况下,它本身就是值,但是在对象的情况下,平等就是内存的位置。
// NOTE: does NOT work
// Create a Set of objects, none of which are assigned to a variable
const avengersSet = Immutable.Set([{ blackWidow: 'Natasha Romanov' }, { captainAmerica: 'Steve Rogers' }]);
// Try to remove blackWidow using the key/value pair, and it won't work
avengersSet.subtract([{ blackWidow: 'Natasha Romanov' }]);
在这个例子中传递给Set的每个对象都存在于一个特定的内存位置,但是因为它没有被分配给一个变量,所以没有办法引用它。仅仅使用键/值对作为subtract()方法中的参数是不够的,因为这只是在不同的内存位置创建单独的对象,因此具有不同的标识。
对于两个被视为相等的对象,您必须创建一个对象,为其分配两个不同的变量,然后比较这些变量是否相等。这样,内存中只有一个对象,分配给它的每个变量指向内存中的单个位置;因此,这两个变量是相等的,因为它们都指向相同的对象。
const obj1 = { key: 'value' };
const obj2 = obj1;
obj1 === obj2;
// OUTPUT: true
将其应用于Set的函数,为了安全地使用对象集合中的相减(subtract),相交(intersect)或联合(union),我们必须创建一组分配的对象:也就是,一组变量,其中每个变量都被分配给一个对象,而不是一组对象直接。
// Create variables and assign them to objects
const blackWidow = {
blackWidow: 'Natasha Romanov'
};
const captainAmerica = {
captainAmerica: 'Steve Rogers'
}
// Create a Set of variables, each of which is assigned to an object
const avengersSet = Immutable.Set([captainAmerica, blackWidow]);
// Output:
avengersSet.subtract([blackWidow]);
[[object Object] {
captainAmerica: "Steve Rogers"
}]
Working with Immutable objects (Map, List, Set, etc.)
由于使用JavaScript对象的困难,Immutable以Immutable.is()方法的形式为其对象(Map,List,Set等)提供了自己的等式方法,它将两个不可变对象视为等于if他们的价值是相等的。
也就是说,即使它们是两个不同的对象(即它们驻留在不同的存储器位置中),以下两个不可变映射也被视为相等:
// Create variables and assign them to objects
const obj1 = Immutable.Map({ key: 'value' });
const obj2 = Immutable.Map({ key: 'value' });
Immutable.is(obj1, obj2);
// OUTPUT: true
这适用于任何不可变的对象,而不仅仅是地图。 Immutable.is()方法由Set的方法在内部使用,以确定在对不可变对象进行操作时的相等性,这使得使用这些对象的集合比使用普通JavaScript对象的集合更容易。
因此,考虑到这一切,让我们看看一些不可变的Set操作实际工作的例子。
Subtract
…a string from a Set of strings
请记住,即使只有一个要减去的值,Set.subtract()中的参数也必须始终是一个数组。
// Subtract an string from a Set of strings
const avengersSet = Immutable.Set(['ironMan', 'captainAmerica', 'blackWidow']);
// Output:
avengersSet.subtract(['blackWidow']);
["ironMan", "captainAmerica"]
…an array of strings from a Set of strings
// Subtract an string from a Set of strings
const avengersSet = Immutable.Set(['ironMan', 'captainAmerica', 'blackWidow']);
avengersSet.subtract(['blackWidow', 'captainAmerica']);
// Output:
["ironMan"]
…an object from a Set of objects
// Subtract an object from a Set of objects
// Subtract blackWidow from avengersSet
const blackWidow = {
blackWidow: 'Natasha Romanov'
};
const avengersSet = Immutable.Set([{
ironMan: 'Tony Stark'
}, {
captainAmerica: 'Steve Rogers'
}, blackWidow]);
// Output:
avengersSet.subtract([blackWidow]);
[[object Object] {
ironMan: "Tony Stark"
}, [object Object] {
captainAmerica: "Steve Rogers"
}]
请注意,名为blackWidow的变量首先分配给对象{blackWidow:'Natasha Romanova'},然后添加为avengersSet的一部分。我们这样做是为了在subtract()方法中使用blackWowow来识别我们要减去的对象。
值得重复的是,您不能使用键/值对来标识要从对象集合中减去的对象:您必须先将对象分配给对象,然后在subtract()方法中使用该变量名称。
…an array of objects from a Set of objects
// Subtract an object from a Set of objects
// Subtract blackWidow and captainAmerica from avengersSet
const blackWidow = {
blackWidow: 'Natasha Romanov'
};
const captainAmerica = {
captainAmerica: 'Steve Rogers'
}
const avengersSet = Immutable.Set([{
ironMan: 'Tony Stark'
}, captainAmerica, blackWidow]);
// Output:
avengersSet.subtract([blackWidow, captainAmerica]);
[[object Object] {
ironMan: "Tony Stark"
}]
…a Map from a Set of Maps
// Subtract a Map from a Set of Maps
// First, create our Maps
const ironMan = Immutable.fromJS([{
ironMan: 'Tony Stark'
}, {
captainAmerica: 'Steve Rogers'
}, {
blackWidow: 'Natasha Romanov'
}]);
// Create a Set of Maps
const avengersSet = Immutable.Set(ironMan);
// Now subtract blackWidow (sorry Natasha)
avengersSet.subtract([Immutable.fromJS({
blackWidow: 'Natasha Romanov'
})]);
// OUTPUT
[[object Object] {
ironMan: "Tony Stark"
}, [object Object] {
captainAmerica: "Steve Rogers"
}]
…a List from a Set of Lists
// Subtract a List from a Set of Lists
// First, create our Lists
const avengers = Immutable.fromJS([
['ironMan', 'Tony Stark'],
['captainAmerica', 'Steve Rogers'],
['blackWidow', 'Natasha Romanov']]);
// Create a Set of Lists
const avengersSet = Immutable.Set(avengers);
// Now subtract ironMan (so long, Tony)
const ironMan = Immutable.List(['ironMan', 'Tony Stark'])
// Remember, subtract requires its arguments to be placed in an array
avengersSet.subtract([ironMan]);
…one Set from another
// Subtract a Set from another Set
// First, create our Sets
const ironMan = Immutable.Set(['ironMan', 'Tony Stark']);
const captainAmerica = Immutable.Set(['captainAmerica', 'Steve Rogers']);
const blackWidow = Immutable.Set(['blackWidow', 'Natasha Romanov']);
// Create a Set of Sets
const avengersSet = Immutable.Set([ironMan, captainAmerica, blackWidow]);
// Now subtract captainAmerica (bye Steve)
avengersSet.subtract([Immutable.Set(['captainAmerica', 'Steve Rogers'])]);
Union
…two sets of strings
// Create a union of two Sets of strings
const avengersCast = Immutable.Set(['ironMan', 'captainAmerica', 'blackWidow']);
const civilWarCast = Immutable.Set(['ironMan', 'antMan', 'spiderMan']);
// Output:
avengersCast.union(civilWarCast);
…a Set of strings and an array of strings
// Create a union of two Sets of strings
const avengersCast = Immutable.Set(['ironMan', 'captainAmerica', 'blackWidow']);
// Output:
avengersCast.union(['ironMan', 'antMan', 'spiderMan']);
…a Set of objects and an object
// Add an object to a set of objects with union
// Add blackWidow to avengersSet
const blackWidow = {
blackWidow: 'Natasha Romanov'
};
const avengersSet = Immutable.Set([{
ironMan: 'Tony Stark'
}, {
captainAmerica: 'Steve Rogers'
}, blackWidow]);
// Output:
avengersSet.union([blackWidow]);
…a Set of Maps and a Map
// Add a Map to a Set of Maps
// First, create our Maps
const ironMan = Immutable.fromJS([{
ironMan: 'Tony Stark'
},{
captainAmerica: 'Steve Rogers'
}]);
// Create a Set of Maps
const avengersSet = Immutable.Set(ironMan);
// Now add blackWidow (hello Natasha)
avengersSet.union([Immutable.Map({
blackWidow: 'Natasha Romanov'
})]);
…a Set of Maps and an object
// Add a Map to a Set of Maps
// First, create our Maps
const ironMan = Immutable.fromJS([{
ironMan: 'Tony Stark'
},{
captainAmerica: 'Steve Rogers'
}]);
// Create a Set of Maps
const avengersSet = Immutable.Set(ironMan);
// Now add blackWidow (hello Natasha)
avengersSet.union([{
blackWidow: 'Natasha Romanov'
}]);
…a Set of Lists and a List
// Add a List to a Set of Lists
// First, create our Lists
const ironMan = Immutable.List(['ironMan', 'Tony Stark']);
const captainAmerica = Immutable.List(['captainAmerica', 'Steve Rogers']);
const blackWidow = Immutable.List(['blackWidow', 'Natasha Romanov']);
// Create a Set of Lists
const avengersSet = Immutable.Set([captainAmerica, blackWidow]);
// Now add ironMan (Hi, Tony)
avengersSet.union([ironMan]);
…two Sets
// Add a Set to another Set
// First, create our Sets
const ironMan = Immutable.Set(['ironMan', 'Tony Stark']);
const captainAmerica = Immutable.Set(['captainAmerica', 'Steve Rogers']);
const blackWidow = Immutable.Set(['blackWidow', 'Natasha Romanov']);
// Create a union of two Sets
const avengersSet = Immutable.Set([ironMan, blackWidow]);
// Now add captainAmerica
avengersSet.union([captainAmerica]);
Intersect
两个集合的交集是仅包含两个集合中存在的那些值的集合。如果一个值存在于集合A中,而不是集合B(反之亦然),那么它不包含在返回的相交集合中。
…two Sets of objects
// Intersect two Sets of objects
// intersect avengersCast with civilWar cast
const blackWidow = {
blackWidow: 'Natasha Romanov'
};
const ironMan = {
ironMan: 'Tony Stark'
};
const captainAmerica = {
captainAmerica: 'Steve Rogers'
};
const theHulk = {
theHulk: 'Bruce Banner'
};
const antMan = {
antMan: 'Scott Lang'
};
const spiderMan = {
spiderMan: 'Peter Parker'
};
const avengersCast = Immutable.Set([ironMan, captainAmerica, blackWidow, theHulk]);
const civilWarCast = Immutable.Set([ironMan, captainAmerica, blackWidow, antMan, spiderMan]);
// Output: who was in Avengers and Civil War?
avengersCast.intersect(civilWarCast);
…two Sets of arrays
// Intersect two Sets of arrays
const ironCapArray = ['ironMan', 'captainAmerica'];
const blackHulkArray = ['blackWidow', 'theHulk'];
const spiderAntArray = ['spiderMan', 'antMan'];
const avengersCast = Immutable.Set([ironCapArray, blackHulkArray]);
const civilWarCast = Immutable.Set([ironCapArray, spiderAntArray]);
// Output:
avengersCast.intersect(civilWarCast);
…two Sets of Maps
// Intersect two Sets of Maps
// First, use fromJS() to create a List of Maps
const avengersCast = Immutable.fromJS([{
blackWidow: 'Natasha Romanov'
}, {
ironMan: 'Tony Stark'
}, {
captainAmerica: 'Steve Rogers'
}, {
theHulk: 'Bruce Banner'
}]);
const civilWarCast = Immutable.fromJS([{
blackWidow: 'Natasha Romanov'
}, {
ironMan: 'Tony Stark'
}, {
captainAmerica: 'Steve Rogers'
}, {
antMan: 'Scott Lang'
}, {
spiderMan: 'Peter Parker'
}]);
// Now create two Sets of Maps
const avengersSet = Immutable.Set(avengersCast);
const civilWarSet = Immutable.Set(civilWarCast);
// Output: who was in Avengers and Civil War?
avengersSet.intersect(civilWarCast);
…two Sets of Lists
// Intersect two Sets of arrays
const ironCapList = Immutable.List(['ironMan', 'captainAmerica']);
const blackHulkList = Immutable.List(['blackWidow', 'theHulk']);
const spiderAntList = Immutable.List(['spiderMan', 'antMan']);
const avengersCast = Immutable.Set([ironCapList, blackHulkList]);
const civilWarCast = Immutable.Set([ironCapList, spiderAntList]);
// Output:
avengersCast.intersect(civilWarCast);
…two Sets of Sets
// Intersect two Sets of arrays
const ironCapSet = Immutable.Set(['ironMan', 'captainAmerica']);
const blackHulkSet = Immutable.Set(['blackWidow', 'theHulk']);
const spiderAntSet = Immutable.Set(['spiderMan', 'antMan']);
const avengersCast = Immutable.Set([ironCapSet, blackHulkSet]);
const civilWarCast = Immutable.Set([ironCapSet, spiderAntSet]);
// Output:
avengersCast.intersect(civilWarCast);