删除集合数组中的子集
Removing subsets in array of Sets
有没有一种从集合数组中删除子集的有效方法
例如数组的数组
[[2, 3, 4, 7, 8, 9, 10], [1, 5, 6], [3, 7, 10], [4, 8, 9], [5, 6], [7, 10], [8, 9], [6], [9]]
输出数组
[[2, 3, 4, 7, 8, 9, 10], [1, 5, 6]]
你可以这样做:
let arrayOfArray = [[2, 3, 4, 7, 8, 9, 10], [1, 5, 6], [3, 7, 10], [4, 8, 9], [5, 6], [7, 10], [8, 9], [6], [9]]
let output = arrayOfArray[0...1]
就像任何其他 (non-2D/set) 数组一样,您可以使用这样的数组扩展...
extension Array
{
func slice(indices:Int...) -> Array
{
var s = indices[0];
var e = self.count - 1;
if (indices.count > 1)
{
e = indices[1];
}
if (e < 0)
{
e += self.count;
}
if (s < 0)
{
s += self.count;
}
let count = (s < e ? e - s : s - e) + 1;
let inc = s < e ? 1 : -1;
var result = Array();
var idx = s;
for i in 0 ..< count
{
result.append(self[idx]);
idx += inc;
}
return result;
}
}
用法:
let a = [[2, 3, 4, 7, 8, 9, 10], [1, 5, 6], [3, 7, 10], [4, 8, 9], [5, 6], [7, 10], [8, 9], [6], [9]];
let b = a.slice(0, 1);
let c = a.slice(3);
如果您的数组不包含重复的 int 值,您可以转换为 Set 以使用 Swift:
中的某些功能
这是我获取另一个不包含子集的数组的代码。此方法未优化,但有效。
//let arrayOfArray = [[2, 3, 4, 7, 8, 9, 10], [1, 5, 6], [3, 7, 10], [4, 8, 9], [5, 6], [7, 10], [8, 9], [6], [9]]
//use set instead
var setArray : [Set<Int>] = [[2, 3, 4, 7, 8, 9, 10], [1, 5, 6], [3, 7, 10], [4, 8, 9], [5, 6], [7, 10], [8, 9], [6], [9]]
setArray.sort({[=10=].count > .count}) //sort to have ordered array (biggest set at first)
var result = [Set<Int>]() //you will get your result in this variable.
for _aSet in setArray {
var isSubSet = false
for _exitSet in result {
if _aSet.isSubsetOf(_exitSet) {
isSubSet = true
break;
}
}
if (!isSubSet) {
result.append(_aSet)
}
}
这是我能想到的最有效的方法:
let nArrays = [[2, 3, 4, 7, 8, 9, 10], [1, 5, 6], [3, 7, 10], [4, 8, 9], [5, 6], [7, 10], [8, 9], [6], [9]]
nArrays
.reduce([Set<Int>]()) {
accu, el in let setEl = Set(el)
return contains(accu) {setEl.isSubsetOf([=10=])} ? accu : accu + [setEl]
}
//[{10, 2, 9, 4, 7, 3, 8}, {5, 6, 1}]
您无需检查每个数组是否是所有其他数组的子集,而只需检查它们是否是已检查数组的子集。当然,returns 是一个 Set 数组,而不是一个数组数组,但是你可以在它上面使用 map() 将它转换回来:
let nArrays = [[2, 3, 4, 7, 8, 9, 10], [1, 5, 6], [3, 7, 10], [4, 8, 9], [5, 6], [7, 10], [8, 9], [6], [9]]
nArrays
.reduce([Set<Int>]()) {
accu, el in let setEl = Set(el)
return contains(accu) {setEl.isSubsetOf([=11=])} ? accu : accu + [setEl]
}
.map{Array([=11=])}
//[[10, 2, 9, 4, 7, 3, 8], [5, 6, 1]]
关键是保证源集按大小降序排列。这样所有的超集都在它们的子集之前。
这是一个通用函数。您可以调整它以采用任何类型的可哈希序列序列,并将它们转换为一组数组:
func removeSubsets<T: Hashable>(source: [Set<T>]) -> [Set<T>] {
let sets = source.sorted { [=10=].count > .count }
var supersets: [Set<T>] = []
for set in sets {
if !contains(supersets, { set.isSubsetOf([=10=]) }) {
supersets.append(set)
}
}
return supersets
}
removeSubsets([[2, 3, 4, 7, 8, 9, 10], [1, 5, 6], [3, 7, 10], [4, 8, 9], [5, 6], [7, 10], [8, 9], [6], [9]])
// returns [{10, 2, 9, 4, 7, 3, 8}, {5, 6, 1}]
不幸的是,它仍然是立方体,因为 contains
是线性的,isSubsetOf
也是。
编辑:这是完全通用的版本:
func removeSubsets
<S0: SequenceType, S1: SequenceType
where S0.Generator.Element == S1,
S1.Generator.Element: Hashable>
(source: S0) -> [Set<S1.Generator.Element>]
{
let sets = map(source) { Set([=11=]) }.sorted { [=11=].count > .count }
var supersets: [Set<S1.Generator.Element>] = []
for set in sets {
if !contains(supersets, { set.isSubsetOf([=11=]) }) {
supersets.append(set)
}
}
return supersets
}
let a: [[Int]] = [
[2, 3, 4, 7, 8, 9, 10],
[1, 5, 6], [3, 7, 10],
[4, 8, 9], [5, 6],
[7, 10], [8, 9],
[6], [9]]
removeSubsets(a) // returns [{10, 2, 9, 4, 7, 3, 8}, {5, 6, 1}]
EDIT2:如果您希望结果是原始数组的数组(因为将它们转换为集合会丢失它们的顺序),您可以进行以下更改,这需要更多 space 但也略微效率更高,因为它只将超集转换为集合,而不是子集:
func removeSubsets<T: Hashable>(source: [[T]]) -> [[T]] {
// note, this is quite efficient since arrays are copy-on-write,
// so it is only really creating a new array of pointers
let sets = source.sorted { [=12=].count > .count }
var supersets: [Set<T>] = []
var result: [[T]] = []
for set in sets {
if !contains(supersets, { [=12=].isSupersetOf(set) }) {
supersets.append(Set(set))
result.append(set)
}
}
return result
}
removeSubsets([[2, 3, 4, 7, 8, 9, 10], [1, 5, 6], [3, 7, 10], [4, 8, 9], [5, 6], [7, 10], [8, 9], [6], [9]])
// returns [[2, 3, 4, 7, 8, 9, 10], [1, 5, 6]]
EDIT3:如果你想保持集合的原始顺序(只删除子集),你可以在排序前用数字标记它们,然后使用它重新排序并去除它最后关闭结果:
func removeSubsets<T: Hashable>(source: [[T]]) -> [[T]] {
let sets = sorted(enumerate(source)) { [=13=].1.count > .1.count }
var supersets: [Set<T>] = []
var result: [(Int,[T])] = []
for (n,set) in sets {
if !contains(supersets, { [=13=].isSupersetOf(set) }) {
supersets.append(Set(set))
result.append(n,set)
}
}
return result.sorted { [=13=].0 < .0 }.map { }
}
// note, input not sorted in order of length
removeSubsets([[1, 5, 6], [2, 3, 4, 7, 8, 9, 10], [3, 7, 10], [4, 8, 9], [5, 6], [7, 10], [8, 9], [6], [9]])
// returns [[1, 5, 6], [2, 3, 4, 7, 8, 9, 10]]
有没有一种从集合数组中删除子集的有效方法
例如数组的数组
[[2, 3, 4, 7, 8, 9, 10], [1, 5, 6], [3, 7, 10], [4, 8, 9], [5, 6], [7, 10], [8, 9], [6], [9]]
输出数组
[[2, 3, 4, 7, 8, 9, 10], [1, 5, 6]]
你可以这样做:
let arrayOfArray = [[2, 3, 4, 7, 8, 9, 10], [1, 5, 6], [3, 7, 10], [4, 8, 9], [5, 6], [7, 10], [8, 9], [6], [9]]
let output = arrayOfArray[0...1]
就像任何其他 (non-2D/set) 数组一样,您可以使用这样的数组扩展...
extension Array
{
func slice(indices:Int...) -> Array
{
var s = indices[0];
var e = self.count - 1;
if (indices.count > 1)
{
e = indices[1];
}
if (e < 0)
{
e += self.count;
}
if (s < 0)
{
s += self.count;
}
let count = (s < e ? e - s : s - e) + 1;
let inc = s < e ? 1 : -1;
var result = Array();
var idx = s;
for i in 0 ..< count
{
result.append(self[idx]);
idx += inc;
}
return result;
}
}
用法:
let a = [[2, 3, 4, 7, 8, 9, 10], [1, 5, 6], [3, 7, 10], [4, 8, 9], [5, 6], [7, 10], [8, 9], [6], [9]];
let b = a.slice(0, 1);
let c = a.slice(3);
如果您的数组不包含重复的 int 值,您可以转换为 Set 以使用 Swift:
中的某些功能这是我获取另一个不包含子集的数组的代码。此方法未优化,但有效。
//let arrayOfArray = [[2, 3, 4, 7, 8, 9, 10], [1, 5, 6], [3, 7, 10], [4, 8, 9], [5, 6], [7, 10], [8, 9], [6], [9]]
//use set instead
var setArray : [Set<Int>] = [[2, 3, 4, 7, 8, 9, 10], [1, 5, 6], [3, 7, 10], [4, 8, 9], [5, 6], [7, 10], [8, 9], [6], [9]]
setArray.sort({[=10=].count > .count}) //sort to have ordered array (biggest set at first)
var result = [Set<Int>]() //you will get your result in this variable.
for _aSet in setArray {
var isSubSet = false
for _exitSet in result {
if _aSet.isSubsetOf(_exitSet) {
isSubSet = true
break;
}
}
if (!isSubSet) {
result.append(_aSet)
}
}
这是我能想到的最有效的方法:
let nArrays = [[2, 3, 4, 7, 8, 9, 10], [1, 5, 6], [3, 7, 10], [4, 8, 9], [5, 6], [7, 10], [8, 9], [6], [9]]
nArrays
.reduce([Set<Int>]()) {
accu, el in let setEl = Set(el)
return contains(accu) {setEl.isSubsetOf([=10=])} ? accu : accu + [setEl]
}
//[{10, 2, 9, 4, 7, 3, 8}, {5, 6, 1}]
您无需检查每个数组是否是所有其他数组的子集,而只需检查它们是否是已检查数组的子集。当然,returns 是一个 Set 数组,而不是一个数组数组,但是你可以在它上面使用 map() 将它转换回来:
let nArrays = [[2, 3, 4, 7, 8, 9, 10], [1, 5, 6], [3, 7, 10], [4, 8, 9], [5, 6], [7, 10], [8, 9], [6], [9]]
nArrays
.reduce([Set<Int>]()) {
accu, el in let setEl = Set(el)
return contains(accu) {setEl.isSubsetOf([=11=])} ? accu : accu + [setEl]
}
.map{Array([=11=])}
//[[10, 2, 9, 4, 7, 3, 8], [5, 6, 1]]
关键是保证源集按大小降序排列。这样所有的超集都在它们的子集之前。
这是一个通用函数。您可以调整它以采用任何类型的可哈希序列序列,并将它们转换为一组数组:
func removeSubsets<T: Hashable>(source: [Set<T>]) -> [Set<T>] {
let sets = source.sorted { [=10=].count > .count }
var supersets: [Set<T>] = []
for set in sets {
if !contains(supersets, { set.isSubsetOf([=10=]) }) {
supersets.append(set)
}
}
return supersets
}
removeSubsets([[2, 3, 4, 7, 8, 9, 10], [1, 5, 6], [3, 7, 10], [4, 8, 9], [5, 6], [7, 10], [8, 9], [6], [9]])
// returns [{10, 2, 9, 4, 7, 3, 8}, {5, 6, 1}]
不幸的是,它仍然是立方体,因为 contains
是线性的,isSubsetOf
也是。
编辑:这是完全通用的版本:
func removeSubsets
<S0: SequenceType, S1: SequenceType
where S0.Generator.Element == S1,
S1.Generator.Element: Hashable>
(source: S0) -> [Set<S1.Generator.Element>]
{
let sets = map(source) { Set([=11=]) }.sorted { [=11=].count > .count }
var supersets: [Set<S1.Generator.Element>] = []
for set in sets {
if !contains(supersets, { set.isSubsetOf([=11=]) }) {
supersets.append(set)
}
}
return supersets
}
let a: [[Int]] = [
[2, 3, 4, 7, 8, 9, 10],
[1, 5, 6], [3, 7, 10],
[4, 8, 9], [5, 6],
[7, 10], [8, 9],
[6], [9]]
removeSubsets(a) // returns [{10, 2, 9, 4, 7, 3, 8}, {5, 6, 1}]
EDIT2:如果您希望结果是原始数组的数组(因为将它们转换为集合会丢失它们的顺序),您可以进行以下更改,这需要更多 space 但也略微效率更高,因为它只将超集转换为集合,而不是子集:
func removeSubsets<T: Hashable>(source: [[T]]) -> [[T]] {
// note, this is quite efficient since arrays are copy-on-write,
// so it is only really creating a new array of pointers
let sets = source.sorted { [=12=].count > .count }
var supersets: [Set<T>] = []
var result: [[T]] = []
for set in sets {
if !contains(supersets, { [=12=].isSupersetOf(set) }) {
supersets.append(Set(set))
result.append(set)
}
}
return result
}
removeSubsets([[2, 3, 4, 7, 8, 9, 10], [1, 5, 6], [3, 7, 10], [4, 8, 9], [5, 6], [7, 10], [8, 9], [6], [9]])
// returns [[2, 3, 4, 7, 8, 9, 10], [1, 5, 6]]
EDIT3:如果你想保持集合的原始顺序(只删除子集),你可以在排序前用数字标记它们,然后使用它重新排序并去除它最后关闭结果:
func removeSubsets<T: Hashable>(source: [[T]]) -> [[T]] {
let sets = sorted(enumerate(source)) { [=13=].1.count > .1.count }
var supersets: [Set<T>] = []
var result: [(Int,[T])] = []
for (n,set) in sets {
if !contains(supersets, { [=13=].isSupersetOf(set) }) {
supersets.append(Set(set))
result.append(n,set)
}
}
return result.sorted { [=13=].0 < .0 }.map { }
}
// note, input not sorted in order of length
removeSubsets([[1, 5, 6], [2, 3, 4, 7, 8, 9, 10], [3, 7, 10], [4, 8, 9], [5, 6], [7, 10], [8, 9], [6], [9]])
// returns [[1, 5, 6], [2, 3, 4, 7, 8, 9, 10]]