2018-12-27 17:23:48 mydo 阅读数 1245

本文向大家介绍稍许算法的实现:关于如何去除数组中的重复元素,并比较了三种算法之间的效率.全部代码在Xcode的Playground中实现,直观明了,适合Swift学习入门童鞋观赏.

有个前提

如题,很多童鞋立即给出解决方法,无外乎是利用Swift内置的集合(Set)或字典(Dict)的一个特性:过滤重复元素.

但由于集合和字典中元素的顺序是无法保证的,所以这建立在一个前提基础之上:结果数组元素顺序和原数组可以不同!

但本文的算法要求:在剔除重复元素之后,元素顺序和原数组必须相同,这正是数组核心特点:有序性的一种体现.

第一种实现

如果想要简单,就必须要多些限制.

如果数组元素能满足Hashable协议,我们利用内置集合也未尝不可:

extension Array where Element:Hashable{
    /// 返回剔除重复元素后的数组,其元素顺序不变
    public var noRepetitionUseSet:[Element]{
        var set = Set<Element>(self)
        var resultAry = [Element]()
        
        for item in self{
            if set.contains(item){
            	//只会保留第一个重复元素!!!
                resultAry.append(item)
                set.remove(item)
            }
        }
        return resultAry
    }
}

如上,我们首先用集合过滤所有重复的元素,然后遍历数组,只保留第一个重复的元素.这样原有数组的顺序即得以保持不变.

数组操作是麻烦之源

如果不能保证数组元素满足Hashable协议,至少它们要满足Equatable协议.

这里略微复杂的地方在于,动态删除数组的元素需要考虑到它们删除的顺序.

删除后的黑洞立即会被后续所填满,仿佛根本不存在一样. — 鲁迅

在这里插入图片描述

还有一个稍微棘手的问题在于:如何计算多个中间数组(它们只是原始数组的部分拷贝)元素在原始数组中对应的索引位置.

所以,这里不如让我们另辟蹊径,利用Swift的另一个特性: Optional!!!

有种类型叫:可有可无!

如果可以解决下面问题,就会使算法简单很多:

  • 不用直接删除重复元素
  • 简化定位元素的位置

这时Optional前来拯救我们了.

其核心思想是:不删除重复元素而是将其设置为nil!!!

extension Array where Element:Equatable{
    public var noRepetition:[Element]{
        var copy:[Element?] = self
        //下面只有非nil值才有比较的必要.
        for (i,x) in copy.enumerated(){
            if x == nil {continue}
            for (j,y) in copy[(i+1)...].enumerated(){
                if y == nil {continue}
                if x! == y! {
                    //将原数组中对应的重复元素设置为nil
                    copy[j+i+1] = nil
                }
            }
        }
        //剔除非空值,保持元素顺序
        return copy.compactMap {$0}
    }
}

如上,算法比较复杂,理解起来略微费劲!

永无止境

这个世界永远有更好的解决方法,就看你能不能发现了.

其实在不使用集合和字典的前提下,我们还可以这么写:

public var noRepetition2:[Element]{
    var result = [Element]()
    for item in self{
        if !result.contains(item) {
            result.append(item)
        }
    }
    return result
}

我们只需要将每一个非重复的元素,放到一个新数组中,就完美的绕开了上面所有这些麻烦的东东…

问题来了:谁更快?快多少?

那么上面3种方法到底谁更快呢???

因为是在Playground中运行,所以很快能写一个性能计算器来得到答案:

struct Timing{
    var start:Date!
    
    mutating func timingStart(){
        start = Date()
    }
    
    func timingStop()->Double{
        return Date().timeIntervalSince(start)
    }
    
    mutating func timing(count:Int,working:()->Void){
        var totalTiming:Double = 0.0
        for _ in 0..<count{
            timingStart()
            working()
            totalTiming += timingStop()
        }
        print("\(count)次平均执行时间 : \(totalTiming/Double(count))")
    }
}

因为系统的复杂性,我们不可能只用一两次执行来统计准确的运行时间.

测试代码如下:

let a = [1,1,1,2,3,4,1,3,4,5,6,2,1,1,1,1,17,7,7,8,9,2,1,0,1]
var t = Timing()
t.timing(count: 1000){
    _ = a.noRepetitionUseSet
}
print(a.noRepetitionUseSet)

t.timing(count: 1000){
    _ = a.noRepetition
}
print(a.noRepetition)

t.timing(count: 1000){
    _ = a.noRepetition2
}
print(a.noRepetition2)

结果如下

1000次平均执行时间 : 0.002724636197090149
[1, 2, 3, 4, 5, 6, 8, 17, 7, 9, 0]
1000次平均执行时间 : 0.004712764143943787
[1, 2, 3, 4, 5, 6, 8, 17, 7, 9, 0]
1000次平均执行时间 : 0.002008106589317322
[1, 2, 3, 4, 5, 6, 8, 17, 7, 9, 0]

首先可以看到三者返回剔除重复元素后的结果是完全一样的(这是必须的),另外它们的速度是第二种比第一种慢大约2ms左右,而最后一种比第一种还快一点点.我想日常的使用还是可以接受的.

(更正:只是对于[1,1,1,2,3,4,1,3,4,5,6,2,1,1,1,1,17,7,7,8,9,2,1,0,1]这个数组来说,第二种比第一种慢2ms,但随着数组元素个数的增加,后者会比前者慢更多!)

结尾

最后总结一下:

  • 第一种算法利用内置集合类,对数组元素类型有限制,但速度快,逻辑简单.
  • 第二种算法依赖更少,但速度稍慢,逻辑略复杂.
  • 第三种算法速度最快,依赖少,逻辑最简单,可以作为首选.

虽然第一种方法利用了内部Swift库的优化,但创建集合的时间抵消了优化的时间,所以最后一种方法胜出!!!

上面我们实现了3种剔除重复元素的算法,并且比较了它们的优劣.

大家可以自由选择,如果你有更好的算法,欢迎讨论 ?

这就是所有的内容了.

(PS:最后还有一种很简单的实现:

public var noRepetition3:[Element]{
    var curIdx = -1
    return self.filter {
        curIdx += 1
        return self.index(of: $0) == curIdx
    }
}

至于原理和速度大家可以遐想一下)

早睡早起,感谢观赏

在这里插入图片描述

2015-09-01 12:09:41 Make___ 阅读数 797

在学习swift的过程中,偶然发现一些问题,而官方的《The Swift Programming Language》中并没有找到相关说明,在此记录一下。


问题是在创建空数组的时候发现的,我们知道在swift中,想要创建空数组,就必须为它指定一个类型,除非当前的上下文已经包含了类型,也即:

var array = []<span style="white-space:pre">	</span>//这样的初始化会报错
var array = [Int]()<span style="white-space:pre">	</span>//正确初始化一个类型为[Int]的空数组

或者当前上下文中已有类型说明时,可以直接创建空数组,例如:

</pre><pre name="code" class="plain">var array = ["1", "2"]<span style="white-space:pre">	</span>//array的类型已经被确定为[String]
array = []<span style="white-space:pre">		</span>//array为一个类型为[String]的空数组


而有的时候,我们想在数组中存放不同类型的数据,就像OC中的NSArray一样,这时,我们有几种方法来初始化一个这样的数组:

1.

var array = [1, "2"]<span style="white-space:pre">	</span>//创建时指定两个类型不同的字面量元素

2.

var array1 = [NSObject]()//创建一个空的数组

3.

var array2 = [1, "2", anyObject]//创建时指定不同类型的字面量元素,且其中包含任意一个类的实例

究竟要说明什么问题呢?

上三种方法,表面上都初始化成功了一个可以存放任意类型数据的数组,但是其实这三个数组的类型各不相同!

从Xcode的自动提示中可以印证这一点:


可以看到,方框中的三个数组array,array2和array3,其类型各不相同。

array是一个存放NSObject类型数据的数组,NSObject显然属于OC范畴,即这个数组中存放的是OC的对象。

array2则是[(NSObject)]类型,这种类型在The Swift Programming Language》中并没有说明,不知道与[NSObject]有何不同?

array3则直接变成了OC中的NSArray类型。

而以上的情况对于其它类型的数据也是一样的,会产生类似于[Int]和[(Int)]这样的数据类型,不知多了一个小括号之后有什么不一样的地方?


猜测在字典类型上也会出现类似情况,但是实际测试发现,字典并未出现这样的情况:








2018-02-24 11:56:39 u011146511 阅读数 390

 

1.*****删除数组中指定元素

 //过滤掉已经选中的cell,这里通过filter过滤掉的到一个新的数组,再把新的数组赋值给原来的数组,swift中没有现成的删除指定元素的方法
            let filterArr  = indexArr.filter {
            $0 != indexPath.item//数组中留下的元素都是不等于indexPath.item
            }
           indexArr=filterArr

var ar6:[String]=[String]()//空数组

var ar4=[Int].init()//创建空数组

var ar5 = Array(repeating: 0.0, count: 3)//默认3个元素

var ar:[String]=["ss"]//var是可变,

let ar2:[String]=["qq"]//let是不可变

    

    ar.append(contentsOf: ["往数组中添加一个数组","ff"])//向数组中添加一个数组

    ar.append("王数组中添加一个元素")//向数组中添加一个元素

        

    ar.replaceSubrange(Range.init(NSMakeRange(0, 1))!, with: ["用于替换数组中的元素"])//替换数组中指定范围的元素

        

//        ar.remove(at: 0)//删除第一个元素

//        ar.removeAll()//删除所有元素

//        ar.removeLast()//删除最后一个元素

//        ar.removeFirst()//删除第一个元素

//        ar.removeSubrange(Range.init(NSMakeRange(0, 1))!)//删除数组中的某个范围

        var ar3=ar+ar2//合并数组

        ar3.insert(contentsOf: ["插入数组"], at: 0)//向数组中插入一个数组

        ar3.insert("插入一个元素", at: 0)//插入一个元素

       let res = ar3.contains("ff")//是否包含ff,结果true

        if res{

            print("包含")

        }

        if let ress:Bool = ar3.contains("ff"){//注意这里的Bool类型必须要加上,否组报错

            print("包括")

        }

        if res == true{

             print("true")

        }

 

数组倒叙排列:leftkeyarr =  leftkeyarr.reversed()

2019-03-18 17:44:43 qq_37269542 阅读数 476

最近项目需求中需要拿到一个list中的某个id 然后将这个id所对应的数据在tableView中置顶。

实现思路:

方法一:首先遍历数组找到这个id所对应的dictionary存下来,然后在已经delete该id所对应dictionary的数组中将该id所对应的dictionary插入到数组的第一位。具体实现代码如下:

        let datas = ["aa","b","cccc","dd","ee"]
        let id = "dd"
        //获取datas中对应为"dd"的数据
        let tempId = datas.filter { (data) -> Bool in
            if id == data {
                return true
            }
            return false
        }.first
        print(tempId) // "dd"
        
        //获取datas中除了"dd"之外的其他数据组成的数组
        var data = datas.filter { (data2) -> Bool in
            if id != data2 {
                return true
            }
            return false
        }
        
        data.insert(tempId!, at: 0)  //将"dd"插入到datas数组的第一位
        print(data) // ["dd", "aa", "b", "cccc", "ee"]

方法二:通过排序来实现:

        let datas = ["aa","b","cccc","dd","ee"]
        let id = "dd"
        let data = datas.sorted { (data1, data2) -> Bool in
            if id == data1{
                return true
            }
            return false
        }
        print(data) // ["dd", "aa", "b", "cccc", "ee"]

 

2017-08-29 15:59:07 xiaoxiaobukuang 阅读数 190

Swift数组使用有序列表存储同一类型的多个值。相同的值可以多次出现在一个数组的不同位置中。
Swift数组会强制检测元素的类型,如果类型不同则会则会报错,Swift数组应该遵循像Array < Element >这样的形式,气宗Element是这个数组中唯一允许存在的数据类型。

如果创建一个数组,并赋值给一个变量,则创建的集合就是可以修改的。这意味着在创建数组后,可以通过添加、删除、修改的方式改变数组里的项目。如果将一个数组赋值给常量,数组就不可更改,并且数组的大小和内容都不可以修改。

注意: 数组初始化时定义了元素类型后,在后续使用中,元素类型必须是统一的。但如果定义了类型为『Any』,或『AnyObject』时,则数组中可以使用任意类型的元素,同时『Any』类型时,还可以包含方法selector类。

一、创建数组

  • 1、使用构造语法来创建一个由特定数据类型构成的空数组:
var someArray = [SomeType]()
  • 2、创建一个初始化大小数组的语法
var someArray = [SomeType](repeating: InitialValue, count: NumbeOfElements)
  • 3、数组的初始化
let arrayTmp01 = Array<String>()  
let arrayTmp02 = [String]()  
let arrayTmp03:Array<String> = []  
let arrayTmp04:[String] = []  
  • 3、例子
let someInts01 = [Int](repeating: 0, count: 3)
print(someInts01)
let someInts02:[Int] = [10, 20, 30]
print(someInts02)

输出:

[0, 0, 0]
[10, 20, 30]

二、数组操作

1、访问数组

可以根据数组的索引来访问数组的元素,语法如下:

var someVar = someArray[index]

index 索引从 0 开始,即索引 0 对应第一个元素,索引 1 对应第二个元素,以此类推。

let array01:[Int] = [1,2,3,4,5]
// 第一个元素
let item01 = array01.first
print(item01)

// 最后一个元素
let item02 = array01.last
print(item02)

// 获取下标未0的元素
let value01 = array01[0]
print(value01)

//查找元素为1的下标
let value02 = array01.index(of: 1)
print(value02)

输出

Optional(1)
Optional(5)
1
Optional(0)

2、数组遍历

let array = ["1", "2", "3", "4"]
for value in array {
    print("value = \(value)")
}
for i in 0..<array.count {
    print(array[i])
}
for (index, value) in array.enumerated() {
    print("index = \(index), value = \(value)")
}

输出:

value = 1
value = 2
value = 3
value = 4
1
2
3
4
index = 0, value = 1
index = 1, value = 2
index = 2, value = 3
index = 3, value = 4

3、添加元素

var array = [1, 2, 3]
// 添加单个元素
array.append(4)
print(array)
//添加元素数组
array = array05 + [5, 6, 7] //
print(array)
//添加元素集合
array.append(contentsOf: [8,9])
print(array)
array.append(contentsOf: 10...15) // 元素序列
print(array)
// 添加元素(添加到指定位置)
array.insert(0, at: 0)
print(array)

输出:

[1, 2, 3, 4]
[1, 2, 3, 4, 5, 6, 7]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]

4、删除元素

var array = [1, 2, 3, 4, 5, 6, 7, 8, 9]
// 删除首个元素
array.removeFirst()
print(array)
// 删除尾部元素
array.removeLast()
print(array)
// 删除指定下标元素
array.remove(at: 0)
print(array)
// 保持数组容量
array.removeAll(keepingCapacity: true)
print(array.capacity)
// 删除所有元素
array.removeAll()
print(array)

输出:

[2, 3, 4, 5, 6, 7, 8, 9]
[2, 3, 4, 5, 6, 7, 8]
[3, 4, 5, 6, 7, 8]
9
[]

5、修改元素

var array = [0, 2, 3]
array[0] = 1
print(array)

输出:

[1, 2, 3]

6、数组元素个数

let array = [1, 2, 3]
// 数组元素个数
let count = array.count
print(count)

输出:

3

7、isEmpty 属性

let array01 = [1, 2, 3]
// 判断数组是否为空
let isValid01 = array01.isEmpty
print(isValid01)
let array02 = [Int]()
let isValid02 = array02.isEmpty
print(isValid02)

输出:

false
true

8、数组是否包含某个元素

let array = [1, 2, 3]
// 是否包含某个元素
let contant: Bool = array.contains(1)
print("array \(contant) 包含 1")

输出:

array true 包含 1

9、数组转字符串

let array = ["1", "2", "3", "4", "5", "6", "7"]
let stringMark: String = "_";
let string = array.joined(separator: stringMark)
print("数组转字符串:\(string)")
let arrayString = string.components(separatedBy: stringMark)
print("字符串转数组:\(arrayString)")

输出:

数组转字符串:1_2_3_4_5_6_7
字符串转数组:["1", "2", "3", "4", "5", "6", "7"]

10、数组排序

let array = [1, 2, 3, 5, 7, 9, 0, 4, 6, 8]
// 数组排序(注意:$0, $1(从0开始,表示第i个参数...))
let arraySort01 = array.sorted { (n1, n2) -> Bool in
    //从小到大
    //return n1 > n2
    //从大到小
    return n1 < n2
}
print(arraySort01)

let arraySort02 = array.sorted(by: {
    // 从小到大
    // return $0 > $1
    // 从大到小
    return $0 < $1
})
print(arraySort02)

let arraySort03 = array.sorted(){
    // 从小到大
    // $0 > $1
    // 从大到小
    $0 < $1
}
print(arraySort03)

输出:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

11、数组的批量操作

// 数组批量操作
var arrayBatch01 = [1,2,3,4,5]
print("1 批量修改:\(arrayBatch01)")
arrayBatch01[1...2] = [8,8]
print("2 批量修改:\(arrayBatch01)")
arrayBatch01.replaceSubrange(Range(uncheckedBounds: (3, 4)), with: [10, 10])
print("3 批量修改:\(arrayBatch01)")

输出:

1 批量修改:[1, 2, 3, 4, 5]
2 批量修改:[1, 8, 8, 4, 5]
3 批量修改:[1, 8, 8, 10, 10, 5]

Swift-数组

阅读数 255

Swift中数组的基本用法

博文 来自: u010026245

Swift3创建数组

阅读数 2944

Swift3数组访问

阅读数 429

没有更多推荐了,返回首页