Showing posts with label Swift 3. Show all posts

[Swift] Use Autolayout programmatically without Storyboard

This is the code test I got from one company's interview. I failed this interview but I think this code test is very fun challenges. Most of time I use storyboard to setup with autolayout, but in the challenge I can't use storyboard. So I need to write it in code. Second, I use uitableview to display data, and it is important to think how to reuse tableview cell, in this project I use cache to save/show photo.

這是前一陣子找工作時候一間公司給的code test. 雖然最後還是沒有成功, 但我覺得這個test很有趣, 一來很短(對方希望你三個小時內完成), 二來可以看到很多基本功。我覺得對方的重點是:
  1. 1.不在storyboard環境下使用Autolayout
  2. 2.Tableview cell的reuse, 特別是圖片的顯示
  3. 3.整個project的架構, 使用了哪些patterns
project架構
基本上重點就在custom cell部分,我把autolayout都寫在這邊
之後有人提醒說使用anthor會比較簡潔,所以我把label和imageview之間的constraint改成用anchor,然後把定義兩個controller和cell之間的"horizontalCons"移到最上面,原來的constrainLeft這個定義就可以拿掉了。  另外UITableView的設定, 在viewDidLoad加入這兩行 避免tableview擋到statusbar:

 self.tableView.contentInset.top = 20
 self.tableView.scrollIndicatorInsets.top = 20

 從URL讀取Image的時候使用loadImageUsingCache 這個extension, 判斷如果有下載過的圖片就先cache起來。 很簡單吧!我覺得這是個很有意思的小作業。
Download Project code: Here

[Swift] flatten nested list

//Given a nested list of integers, implement an iterator to flatten it.
//
//Each element is either an integer, or a list -- whose elements may also be integers or other lists.
//
//Example 1:
//Given the list [[1,1],2,[1,1]],
//
//By calling next repeatedly until hasNext returns false, the order of elements returned by next should be: [1,1,2,1,1].

[Swift] anagrams group


// Given an array of words, print all anagrams together. For example, if the given array is {“cat”, “dog”, “tac”, “god”, “act”}, then output may be “cat tac act dog god”.

說明:給一個String array, 把裡面字串相同字的group在一起後輸出。
解法: 
1. Put source array in to set A
2. for loop every element in the string array if element's sorted char is equal first element. If found put into an array B.
3. remove set A's element same in the array B and put it to for loop function again.



Binary Search Tree with Swift



主要有兩個物件,Tree 和 Node, Node 代表Tree裡面的每個節點, 然後節點存有自己及left , right的子節點。

1. 將節點加到樹的規則(Add node to tree):

  • 如果樹完全沒有節點,第一個加入的就是root
  • 之後加入的如果加入的值比節點小,就放到left child。如果比較大就放到right child。放的時候檢查如果該子節點已經有值,繼續遞迴往下搜尋到沒有值的地方存放。

2. 顯示排序節點from smallest to biggest(Depth-First Search in-order) traverse:

A-B-C-D-E-F-G-I-H

  • 從最左邊(最小的)開始找,如果已經找不到left child代表已經是最小的,然後print出來。
  • 然後檢查有沒有right child,繼續遞迴去找。
  • Big O:  O(n)
Pre-order traverse:
F-B-A-D-C-E-F-I-H
  • 顯示current node, 然後再顯示左邊子節點, 再來右邊子結點
Post-order traverse:
A-C-E-D-B-H-I-G-F
  • 遞迴顯示左邊子結點, 如果都巡覽完了再遞迴找右邊節點, 然後再顯示current node. 
3. Remove node from tree:
  • Check first if root exists. If not then return.
  • Find the node to remove.
    • If node doesn't have child, direct remove it.
    • If node have one child, copy child's value to it then remove child.
    • If node have 2 child:
      •  find a minimum value in the node's right subtree.
      •  replace value of the node to be removed with found minimum.
      •  remove to the right subtree to remove a duplicate(original minimum value in the node's right subtree).


參考:



GCD (Grand Central Dispath)

What is GCD?
GCD is the dispatch queue. A queue is actually a block of code that can be executed synchronously or asynchronously, either on the main or on a background thread. Queues are following the FIFO pattern. Next, another important concept is the work item. A work item is literally a block of code that is either written along with the queue creation, or it gets assigned to a queue and it can be used more than once (reused).


DispatchQueue  - manage tasks you submit and execute them in a FIFO order guaranteeing that the first task submitted is the first one started. Tasks that you submit to a DispatchQueue are encapsulated by DispatchWorkItem. You can configure the behavior of a DispatchWorkItem such as its QoS class or whether to spawn a new detached thread.

Queues can be either serial or concurrent. 
   

GCD provides three main types of queues:

  1. Main queue: runs on the main thread and is a serial queue. The main thread must be always remain free so it serves the user interface and user interactions. Any time-consuming or CPU demanding tasks should run on concurrent or background queues.
  2. Global queues: concurrent queues that are shared by the whole system. There are four such queues with different priorities : high, default, low, and background. The background priority queue is I/O throttled.
  3. Custom queues: queues that you create which can be serial or concurrent. These actually trickle down into being handled by one of the global queues.

The Quality of Service(QoS) priority are:
  • User-interactive: This represents tasks that need to be done immediately in order to provide a nice user experience. Use it for UI updates, event handling and small workloads that require low latency. The total amount of work done in this class during the execution of your app should be small. This should run on the main thread.
  • User-initiated: The represents tasks that are initiated from the UI and can be performed asynchronously. It should be used when the user is waiting for immediate results, and for tasks required to continue user interaction. This will get mapped into the high priority global queue.
  • Utility: This represents long-running tasks, typically with a user-visible progress indicator. Use it for computations, I/O, networking, continous data feeds and similar tasks. This class is designed to be energy efficient. This will get mapped into the low priority global queue.
  • Background: This represents tasks that the user is not directly aware of. Use it for prefetching, maintenance, and other tasks that don’t require user interaction and aren’t time-sensitive. This will get mapped into the background priority global queue.




ref: 
https://www.raywenderlich.com/148513/grand-central-dispatch-tutorial-swift-3-part-1
https://www.appcoda.com/grand-central-dispatch/

TitleAnimation for scroll down tableview[下拉tableview顯示title]

Demo code: github


Xcode Server Screenshot:





Dynamic UIImageView Size within UITableview [動態調整Imageview圖片高度]

OK, This is one of my code test problem when I interview iOS developer. In that time I didn't answer very well and I didn't get that job. But after I reorganized it, it's not so difficult to do it.

So, support we went download image from url and show it on UITableView, and we need to dynamic the ImageView in case some images are portrait, and some are landscape.

If we not doing anything, then they will look like:


As we can see first one is landscape image, but second one is portrait. And second one's image is squeezed by its frame. So we need to do some change when image is portrait.


Here is way we do:

1. Download image from internet url (we use SDWebImage sdk) and show on tableview
2. In  tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) we calculated the images ratio.
3. If is portrait image, then we update this row.


Here is demo code you can download: github

*In this project, you also can see I use custom class to save json data.

UITableview multi-custom cell [UITableview 使用多個自訂cell的處理]

It's easy to display tableview if just one cell templete, but when comes more then 2 or 3 different cells what to show on same UITableview, it will become very mass if we put all our logic code in side the fuction.

Just looks like:



So we put those codes in different methods and return to UITableViewCell , Then the code will look more clear.

Then we put the return cell into another function:

See! code looks much better!

Download source code here

iOS interview questions that I've been asked

最近面試問到的一些問題, 記錄一下:

1. What is cocoa and cocoa touch?

Cocoa and Cocoa Touch are the application development environments for OS X and iOS, respectively. Both Cocoa and Cocoa Touch include the Objective-C runtime and two core frameworks:
  • Cocoa, which includes the Foundation and AppKit frameworks, is used for developing applications that run on OS X.
  • Cocoa Touch, which includes Foundation and UIKit frameworks, is used for developing applications that run on iOS.

2. What's different between NULL and nil and Nil?

The difference is that while NULL represents zero for any pointer, nil is specific to objects (e.g., id) and Nil is specific to class pointers.

Swift’s nil is not the same as nil in Objective-C. In Objective-C, nil is a pointer to a non-existent object. In Swift, nil is not a pointer—it is the absence of a value of a certain type. Optionals of any type can be set to nil, not just object types.

3. What's different between 'weak' and 'strong' property?

weak: will assign the incoming value to it without retaining it. You don't want to have control over the object's lifetime.

strong: (default)assigns the incoming value to it, it will retain the incoming value and release the existing value of the instance variable. The compiler will take care that any object that you assign to this property will not be destroyed as long as you point to it with a strong reference. Only once you set the property to nil will the object get destroyed.

strong属性指的是对这个对象强烈的占有!不管别人对它做过什么,反正你就是占有着!它对于你随叫随到。weak指的是对这个对象弱弱的保持着联系,每次使用的时候你弱弱的问它一句“还在吗”,如果没人回应(变成nil),就说明它已经离开你了(大概是被系统残忍的回收了吧)。

链接:https://www.zhihu.com/question/20350816/answer/22307399


retain cycle: Two objects hold a strong reference to each other, such that each instance keeps the other alive, the reference counts do not drop to zero, and the instances are not deallocated by ARC. This is known as a strong reference cycle. 



3.1. What is the difference between a weak reference and an unowned reference?

Both weak and unowned references do not create a strong hold on the referred object (a.k.a. they don't increase the retain count in order to prevent ARC from deallocating the referred object).

A weak reference allows the posibility of it to become nil (this happens automatically when the referenced object is deallocated), therefore the type of your property must be optional - so you, as a programmer, are obligated to check it before you use it (basically the compiler forces you, as much as it can, to write safe code).


An unowned reference presumes that it will never become nil during it's lifetime. A unowned reference must be set during initialization - this means that the reference will be defined as a non-optional type that can be used safely without checks. If somehow the object being referred is deallocated, then the app will crash when the unowned reference will be used.

A weak reference is just a pointer to an object that doesn't protect the object from being deallocated by ARC. While strong references increase the retain count of an object by 1, weak references do not.


4. What is ARC?

Automatic Reference Counting (ARC) is a compiler feature that provides automatic memory management of Objective-C objects. Rather than having to think about retain and release operations, ARC allows you to concentrate on the interesting code, the object graphs, and the relationships between objects in your application.

#automatic memory management, dealloc


5. What is atomic?

With "atomic", the synthesized setter/getter will ensure that a whole value is always returned from the getter or set by the setter, regardless of setter activity on any other thread.

atomic vs. nonatomic refers to the thread safety of the getter and setter methods that the compiler synthesizes for the property. atomic (the default) tells the compiler to make the accessor methods thread-safe (by adding a lock before an ivar is accessed) and nonatomic does the opposite. The advantage of nonatomic is slightly higher performance.

#atomic -> thread safety, nonatomic -> faster

6. What is BLOCK?

Blocks are a way of defining a single task or unit of behavior without having to write an entire Objective-C class.

You can use blocks to compose function expressions that can be passed to API, optionally stored, and used by multiple threads. Blocks are particularly useful as a callback because the block carries both the code to be executed on callback and the data needed during that execution.

#like closures in swift, callback API

7. What's different between CLASS and STRUCTURE in swift? 

The main difference is that structs are value types and classes are reference types. Structures cannot inherit from other types.

Structs are preferable if they are relatively small and copiable because copying is way safer than having multiple reference to the same instance as happens with classes.

Structs there is much less need to worry about memory leaks.

8. What is a protocol?

It defines a list of required and optional methods that a class must/can implement if it adopts the protocol.

#define , required or optional methods, blueprint

9. What is UIAppliction?

UIApplication is the iOS singleton application base class.  It's a major role of  app’s application object is to handle the initial routing of incoming user events.


10. What is UIView? How to create custom UIView?

UIView is an object that manages the content for a rectangular area on the screen, it responsible for recognizing touches, gestures.

To create custom uiview, just create your own class subclassing UIView, then override initWithFrame or drawRect.

11. Optional type

A type that can represent either a wrapped value or nil. It shows the wrapped type's name with a trailing question mark (?). There are couple ways to unwrapping :  if let statement , guard statement, forced unwrapping. But forced unwrapping triggers a runtime error when the optional is nil. We should try to avoid it.

A common example of implicitly unwrapped optionals is how view controller define their IBOutlets.
It would be unwieldy(笨重的) to always unwrap each view outlet inside view controllers.

#question mark, exclamation mark, unwrapping 

11.1 Optional Chain
Optional chaining is a process for querying and calling properties, methods, and subscripts on an optional that might currently be nil. If the optional contains a value, the property, method, or subscript call succeeds; if the optional is nil, the property, method, or subscript call returns nil. Multiple queries can be chained together, and the entire chain fails gracefully if any link in the chain is nil.

12. NSKeyedArchiver
Core data, NSKeyedArchiver and UserDefaults are three ways in which a programmer can persist data in between app launches. Though core data is slightly more complicated, it is useful when the stored information requires structure. NSKeyedArchiver is less complex and slower than core data, but is much simpler to use. UserDefaults is the simplest method to persist data.

13. Access Control

Open access and public access enable entities to be used within any source file from their defining module, and also in a source file from another module that imports the defining module. You typically use open or public access when specifying the public interface to a framework. The difference between open and public access is described below:

  • An open class is accessible and subclassable outside of the defining module. An open class member is accessible and overridable outside of the defining module.
  • A public class is accessible but not subclassable outside of the defining module. A public class member is accessible but not overridable outside of the defining module.


Internal access enables entities to be used within any source file from their defining module, but not in any source file outside of that module. You typically use internal access when defining an app’s or a framework’s internal structure.

File-private access restricts the use of an entity to its own defining source file. Use file-private access to hide the implementation details of a specific piece of functionality when those details are used within an entire file.

Private access restricts the use of an entity to the enclosing declaration, and to extensions of that declaration that are in the same file. Use private access to hide the implementation details of a specific piece of functionality when those details are used only within a single declaration.

Open access is the highest (least restrictive) access level and private access is the lowest (most restrictive) access level.

簡單來說:
keep private details of a class hidden from the rest of the app
keep internal details of a framework hidden from the client app


14. What is Core Data?

Core Data is a framework for managing an object graph. An object graph is nothing more than a collection of interconnected objects.

Core Data is not a database. 
Core Data isn't thread safe. Core Data expects to be run on a single thread.


How to use it?

When you start a new project in Xcode and open the template selection dialog, select the Use Core Data checkbox. A source file for the Core Data model is created as part of the template. That source file will have the extension .xcdatamodeld. Select that file in the navigator area to display the Core Data model editor.

1. open new project and check with "use Core Data"
2. open file have extension .xcdatamodelid, then xcode will display Cor Data model editor.
3. create entity and create attributes and relationships for the entity.
4. use NSManagedObject to manage data. (NSManagedObject represents a single object stored in Core Data; you must use it to create, edit, save and delete from your Core Data persistent store.)
5. NSFetchRequest is the class responsible for fetching from Core Data.


15. What is Grand Central Dispath(GCD)?

GCD is a low-level C-based API that enables very simple use of a task-based concurrency model. A queue is actually a block of code that can be executed synchronously or asynchronously, either on the main or on a background thread. Queues are following the FIFO pattern.
Another important concept is the work item. A work item is literally a block of code that is either written along with the queue creation, or it gets assigned to a queue and it can be used more than once (reused).

When to Go for GCD or NSOperation?

when you want more control over queue (all above mentioned) use NSOperation and for simple cases where you want less overhead (you just want to do some work "into the background" with very little additional work) use GCD.

16. What is different between Frame and Bounds?

frame = a view's location and size using the parent view's coordinate system.(relative to the superview)
Important for: placing the view in the parent

bounds = a view's location and size using its own coordinate system
Important for: placing the view's content or subviews within itself

17. UIViewcontroller lifecircle

  • ViewDidLoad - Called when you create the class and load from xib. Great for initial setup and one-time-only work. It might be called several times if the view is unloaded due to low memory and then loaded again.
  • ViewWillAppear - Called right before your view appears, good for hiding/showing fields or any operations that you want to happen every time before the view is visible. Because you might be going back and forth between views, this will be called every time your view is about to appear on the screen.
  • ViewDidAppear - Called after the view appears - great place to start an animations or the loading of external data from an API.
  • ViewWillDisappear/DidDisappear - Same idea as ViewWillAppear/ViewDidAppear.
18. Singletion class

A singleton class returns the same instance no matter how many times an application requests it. A singleton object provides a global point of access to the resources of its class. Singletons are used in situations where this single point of control is desirable, such as with classes that offer some general service or resource.

use the @synchronized pattern - and @synchronized is still the best way to do simple locking in Objective-C.

19. Closures

Closures are self-contained blocks of functionality that can be passed around and used in your code. Closures in Swift are similar to blocks in C and Objective-C and to lambdas in other programming languages.

20. Autolayout

Auto Layout dynamically calculates the size and position of all the views in your view hierarchy(階層), based on constraints placed on those views.

21. Safe area

The Safe Area is the area in between System UI elements which are Status Bar, Navigation Bar and Tool Bar or Tab Bar. After iOS11, you can use SafeAreaLayoutGuide. By add constraints between your content and safe area anchors. This prevents your content from being obscured(模糊, 遮擋) by top and bottom bars.



[Swift] Sort custom class(struct) object array


//Post structure 
class Post: NSObject {
    var uid: String
    var title: String
    var body: String
    var time: String
    var imagePath : String
    init(uid: String, title: String, body: String, time: String, imagePath: String) {
        self.uid = uid
        self.title = title
        self.body = body
        self.time = time
        self.imagePath = imagePath
    }
}


var postAr = [Post]()

//add element in to array...
........
//Sort array
postAr = postAr.sorted(by: { $0.time > $1.time })


last line is key....In Addition, we can using map, filter or reduce to operate on Swift collection types.

You can see how to use in here







[Swift] set UILabel fade-in fade-out continuity

extension UILabel {
    /**
     Set Text With animation fadein fadeout
     - parameter duration: NSTimeInterval?
     */
    public func setTextAnimation(duration: TimeInterval?, completion:(()->())? = nil) {
        UIView.animate(withDuration: duration!, delay: 0.0, options: UIViewAnimationOptions.curveEaseOut, animations: {
            self.alpha = 0.0
        }, completion: {
            (finished: Bool) -> Void in
            // Fade in
            UIView.animate(withDuration: duration!, delay: 0.0, options: UIViewAnimationOptions.curveEaseIn, animations: {
                self.alpha = 1.0
            }, completion: {
                (finished: Bool) -> Void in
                self.setTextAnimation(duration: duration!)
            })
        })
    }

}

[Swift] Assign Cookies

Assume you are an awesome parent and want to give your children some cookies. But, you should give each child at most one cookie. Each child i has a greed factor gi, which is the minimum size of a cookie that the child will be content with; and each cookie j has a size sj. If sj >= gi, we can assign the cookie j to the child i, and the child i will be content. Your goal is to maximize the number of your content children and output the maximum number.
Note:
You may assume the greed factor is always positive.
You cannot assign more than one cookie to one child.
Example 1:
Input: [1,2,3], [1,1]

Output: 1

Explanation: You have 3 children and 2 cookies. The greed factors of 3 children are 1, 2, 3.
And even though you have 2 cookies, since their size is both 1, you could only make the child whose greed factor is 1 content.
You need to output 1.
Example 2:
Input: [1,2], [1,2,3]

Output: 2

Explanation: You have 2 children and 3 cookies. The greed factors of 2 children are 1, 2.
You have 3 cookies and their sizes are big enough to gratify all of the children,
You need to output 2.

兩個陣列都要先排序過,然後依序將每個餅乾和小孩去配看是否符合,記得分配過的餅乾和小朋友就要跳過。


        var Ars_g = g.sorted()
        var Ars_s = s.sorted()
        var res = 0
        if (Ars_g.count > 0 && Ars_s.count > 0) {
            var i=0, j=0
            while j < Ars_s.count {
                while i < Ars_g.count {
                    //print("Ars_g[i]: \(Ars_g[i]), Ars_s[j]: \(Ars_s[j])")
                    if Ars_g[i] <= Ars_s[j] {
                        res += 1
                        j += 1
                    }
                    if j >= Ars_s.count { break }
                    i += 1
                }
                
                j += 1
                i = res
            }
        }

        return res


[Swift] Add Digits

Given a non-negative integer num, repeatedly add all its digits until the result has only one digit.
For example:
Given num = 38, the process is like: 3 + 8 = 111 + 1 = 2. Since 2 has only one digit, return it.

把數字轉成文字然後拆開,遞迴相加後直到剩一個字元
--------------------

func addDigits(_ nums: Int) -> Int {
    
    var numsChar = String(nums).characters
    while (numsChar.count > 1){
        var sum = 0
        for char in numsChar {
            let intchar = String(char)
            sum = sum + Int(intchar)!
        }
        numsChar = String(sum).characters
    }
    return Int(String(numsChar))!

}

[Swift] Roman to Integer

Given a roman numeral, convert it to an integer.

Input is guaranteed to be within the range from 1 to 3999.

解法:


    //兩兩拆開 從最後一個數開始看
    //ex: XLV -> XL + V = 50-10 + 5 = 45
    //XLIX -> XL + IX = 50-10 + 10-1 = 49
    //拆開後兩兩相比 高位在前用加法 低位在前用減法
    //XL = X 比 L 小 , 所以用減法 = ABS(10 - 50) = 40
    //LX = 高位在前用加法 = L + X = 10 + 50
    //LXXXIX = LX + XX + IX = 60 + 20 + ABS(1-10) = 89

----------------------------------------------
class Solution {
    func romanToInt(_ s: String) -> Int {
       
    var dict = ["M":1000,"D":500,"C":100,"L":50,"X":10,"V":5,"I":1]
 
    var ret = 0
 
    var charAr = Array(s.characters)

    while (charAr.count > 0) {
           if (charAr.count >= 2){
                let ch1 = dict[String(charAr[0])]
                let ch2 = dict[String(charAr[1])]
             
                if ch1! >= ch2! {
                    ret = ret + ch1!
                    //算完拿掉 避免重算
                    charAr.removeFirst()
                }else{
                    ret = ret + abs(ch1! - ch2!)
                    charAr.removeFirst()
                    charAr.removeFirst()
                }

         
            }else{
                //剩一個的情況
                let ch1 = dict[String(charAr[0])]
                ret = ret + ch1!
                charAr.removeFirst()
            }
         
        }
 
    return ret
    }
}


[Swift] Reverse Integer

Reverse digits of an integer.
Example1: x = 123, return 321
Example2: x = -123, return -321


//Way1 mod取餘數去解
func reverse2(_ x: Int) -> Int {
    var y = x
    var returnVal = 0
    while (y != 0){
        returnVal = 10*returnVal + y%10
        y = y / 10
    }
    
    if (returnVal>Int.max || returnVal<Int.min) {
        return 0
    }else{
        return returnVal
    }
    
}

//Way2 string去解
func reverse(_ x: Int) -> Int {
    if x > Int.max || x < Int.min || x == 0 { return 0 }
    var returnVal = x
    var isNagative:Bool = false
    if x < 0 {
        isNagative = true
        returnVal = abs(x)
    }
    let myString = String(String(returnVal).characters.reversed())
    if Int(myString) != nil {
        if isNagative == true {
            return 0-Int(myString)!
        }else{
            return Int(myString)!
        }
    }else{
        return 0
    }
    
}

[Swift] 3Sum

Given an array S of n integers, are there elements abc in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.
Note:
  • Elements in a triplet (a,b,c) must be in non-descending order. (ie, a ≤ b ≤ c)
  • The solution set must not contain duplicate triplets.
For example, given array S = {-1 0 1 2 -1 -4},

A solution set is:
(-1, 0, 1)
(-1, -1, 2)


解法: 
https://www.youtube.com/watch?v=-AMHUdZc9ss
利用前後兩個指標和最左邊開始的數相加去比對。



func threeSum(_ nums: [Int]) -> [[Int]] {
    var returnArray = [[Int]]() //Array for saved and return
    
    if (nums.count < 3) {return returnArray}
    
    let orgArray = nums.sorted() //sort array first
    
    
    for i in 0...orgArray.count - 3 {
        if i == 0 || orgArray[i] > orgArray[i - 1] {
           //左右兩邊的pointer
           var start = i + 1
           var end = orgArray.count - 1
            
            while ( start < end ) {
                //如果相加等於0 就存入要回傳的陣列中
                if (orgArray[i] + orgArray[start] + orgArray[end] == 0) {
                    let newap = [orgArray[i] , orgArray[start] , orgArray[end]]
                    returnArray.append(newap)
                }
                //如果三個加起來比0還小 , 則移動start 這個pointer
                if (orgArray[i] + orgArray[start] + orgArray[end] < 0) {
                    let currentStart = start
                    //如果pointer[A] pointer[A+1] 相同的話就直接跳下一個
                    while (orgArray[start] == orgArray[currentStart] && start < end) {
                        start += 1
                    }
                }else{
                    let currentEnd = end
                    while (orgArray[end] == orgArray[currentEnd] && start < end) {
                        end -= 1
                    }
                }
            }
        }
    }
    return returnArray

}