Swift - Find duplicates Elements in a List - ios

i have the following list of UITextField:
let list = [(name1TextField, phone1TextField), (name2TextField, phone2TextField), (name3TextField, phone3TextField), (name4TextField, phone4TextField), (name5TextField, phone5TextField)]
i'm trying to find phones duplicates and print them out
EDIT
e.g. (tuples could be empty)
list = [("john", "555-444-333"), ("james", "555-444-333"), ("",""), ("bob", "333-222-111"), ("nancy", "222-111-444"), ]
output 555-444-333
how can i do?

Given this
var name1TextField: UITextField!
var phone1TextField: UITextField!
var name2TextField: UITextField!
var phone2TextField: UITextField!
var name3TextField: UITextField!
var phone3TextField: UITextField!
var name4TextField: UITextField!
var phone4TextField: UITextField!
var name5TextField: UITextField!
var phone5TextField: UITextField!
And this
let list = [(name1TextField, phone1TextField), (name2TextField, phone2TextField), (name3TextField, phone3TextField), (name4TextField, phone4TextField), (name5TextField, phone5TextField)]
Solution
let repeatedPhones = list
.flatMap { $0.1?.text }
.reduce([String:Int]()) { (var dict, phone) -> [String:Int] in
dict[phone] = (dict[phone] ?? 0) + 1
return dict
}
.filter { $0.1 > 1 && !$0.0.isEmpty }
.map { $0.0 }

Using dictionary to record how many time you see a phone number:
var dict = [String: Int]()
And then go thru the whole list:
for (_, phone) in list {
if let count = dict[phone] {
dict[phone] = count + 1
} else {
dict[phone] = 1
}
}
After this you will have a dictionary which contains the phone number and the count of each phone number appear in the list
for item in dict {
if item.1 > 1 {
print(item.0)
}
}
This method has a time complexity: O(2n)
And this question looks like a duplicate of Find Duplicate Elements In Array Using Swift

You can create a list of the last tuple items and then, as you add them to a new array, check if they are already contained in the array.
So something like:
func processList(list) -> String {
var bufferArray[String] = []
for (int i = 0; i < list.size; i++) {
if !(bufferArray.contains( list[i].1 )) {
bufferArray.add(list[i].1)
else {
return list[i].1
}
}
}

What I would do is the following:
var duplicates = []
var set = Set<String>()
for tuple in list {
if set.contains(tuple.phoneTextField.text) {
duplicates.append(tuple.phoneTextField.text)
} else {
set.insert(tuple.phoneTextField.text)
}
}
At the end you would do whatever you want with the duplicates array.

Related

Not Repeating Word in Swift when clicking button - IOS

How can I not repeat the array when I click on the button in swift? I'm trying to generate fruits without them repeating.
import UIKit
class fruitrandomViewController: UIViewController {
#IBOutlet weak var nextfruitButton: UIButton!
#IBOutlet weak var fruitbox: UILabel!
#IBAction func fruitbutton(_ sender: UIButton) {
let array = ["Apple","Banana","Orange","Pinapple", "Plum", "Pear",]
let randomFruitgenerator = Int(arc4random_uniform(UInt32(array.count)))
fruitbox.text = array[randomFruitgenerator]
}
}
My suggestion is to use a Set and remove the random item from the set
var set = Set(["Apple","Banana","Orange","Pinapple", "Plum", "Pear"])
#IBAction func fruitbutton(_ sender: UIButton) {
if let fruit = set.randomElement() {
fruitbox.text = fruit
set.remove(fruit)
} else {
fruitbox.text = "" // or whatever to indicate that the set is empty
}
}
My suggest:
You can random each item 1 time
let originFruits = ["Apple","Banana","Orange","Pinapple", "Plum", "Pear"]
let array = originFruits
#IBAction func fruitbutton(_ sender: UIButton) {
...
let fruitRandom = array random
array delete fruitRandom
if (array empty) {
array = originFruits
}
}
You can check and remove in next time
let originFruits = ["Apple","Banana","Orange","Pinapple", "Plum", "Pear"]
let array = originFruits
let skipFruit = ""
#IBAction func fruitbutton(_ sender: UIButton) {
...
array = originFruits
array delete skipFruit
let fruitRandom = array random
skipFruit = fruitRandom
}
I think this will work, but I think it's Time Complexity can be O(n) as I am assuming that there is a possibility of randomElement return Apple every time and savedFruit is also Apple, so in that case, the Time Complexity will be O(n). A better workaround will be to remove that element from that array so, the next time the randomElement will be different for sure. Then, once it is different you can append the old one and remove the current one. I hope it makes sense to you, but for now this will work I think:
let array = ["Apple","Banana","Orange","Pinapple", "Plum", "Pear"]
var savedFruit = String()
func fetchRandomFruit() {
if let fruit = array.randomElement() {
if fruit != savedFruit { //Here it will check if the last element is same as the new randomElement
savedFruit = fruit
fruitbox.text = savedFruit
} else {
fetchRandomFruit()
}
}
}
#IBAction func fruitbutton(_ sender: UIButton) {
fetchRandomFruit()
}
Use fruitbox.text = array.randomElement() ?? "default value for if array is empty". This is not guaranteed not to repeat, but is random.
If you want to ensure it does not repeat, use this
var new = array.randomElement() ?? fruitbox.text
while new == fruitbox.text {
new = array.randomElement() ?? fruitbox.text
}
fruitbox.text = new
This WILL loop infinitely (until it crashes) if the array is empty.

How to use for loop to create Int array in Swift 3

I know this is a very basic question,
But I try lot methods, and always show:
"fatal error: Array index out of range"
I want to create a 0~100 int array
e.q. var integerArray = [0,1,2,3,.....,100]
and I trying
var integerArray = [Int]()
for i in 0 ... 100{
integerArray[i] = i
}
There are also appear : fatal error: Array index out of range
Thanks for help
Complete code:
class AlertViewController: UIViewController,UIPickerViewDelegate, UIPickerViewDataSource {
#IBOutlet weak var integerPickerView: UIPickerView!
#IBOutlet weak var decimalPickerView: UIPickerView!
var integerArray = [Int]()
var decimalArray = [Int]()
override func viewDidLoad() {
super.viewDidLoad()
giveArrayNumber()
integerPickerView.delegate = self
decimalPickerView.delegate = self
integerPickerView.dataSource = self
decimalPickerView.dataSource = self
}
func giveArrayNumber(){
for i in 0 ... 100{
integerArray[i] = i
}
}
Your array is empty and you are subscripting to assign value thats why you are getting "Array index out of range" crash. If you want to go with for loop then.
var integerArray = [Int]()
for i in 0...100 {
integerArray.append(i)
}
But instead of that you can create array simply like this no need to use for loop.
var integerArray = [Int](0...100)
Without using loops:
var integerArray = Array(0...100)
Without using loops 2:
var integerArray = (0...100).map{ $0 }
Without using loops 3:
var integerArray = [Int](0...100)
Using loops (better do not use) :
var integerArray = [Int]()
for i in 0...100 { integerArray.append(i) }
Because your array is empty, so the "integerArray[i] (where i is 1 for example)" doesn't exist.
You have to write something like this :
func giveArrayNumber() {
for i in 0 ... 100{
integerArray.append(i)
}
}

How to get the unique id's of objects in an array swift

I have a custom class like this -
class Event: NSObject
{
var eventID: String?
var name:String?
}
Now i have an array of Event object's like
var events = [Event]()
var event1 = Event()
event1.eventID = "1"
event1.name = "Anu"
var event2 = Event()
event2.eventID = "2"
event2.name = "dev"
var event3 = Event()
event3.eventID = "1"
event3.name = "Anu"
events.append(event1)
events.append(event2)
events.append(event3)
to get the unque eventID's from array i have written code like this which is working great -
func getUniqueIDsFromArrayOfObjects(events:[Event])->NSArray
{
let arr = events.map { $0.eventID!}
let uniquearr:NSMutableArray = NSMutableArray()
for obj in arr
{
if !uniquearr.containsObject(obj) {
uniquearr.addObject(obj)
}
}
return uniquearr;
}
print(getUniqueIDsFromArrayOfObjects(events))
I wanted to know is there any alternate way to get the unique id's from array of objects more effectively than i am using . May be something by using NSPredicate.
Because an array having thousands of objects, my code going to do more iteration .
You can use a Set to obtain only the unique values. I would suggest that you have your function return a Swift array rather than NSArray too.
func getUniqueIDsFromArrayOfObjects(events:[Event])->[String]
{
let eventIds = events.map { $0.eventID!}
let idset = Set(eventIds)
return Array(idset)
}
let uniqueRecords = jobs.reduce([], {
$0.contains($1) ? $0 : $0 + [$1]
})
A Set is a collection similar to an array, which prevents duplicates. You can do:
func getUniqueIDsFromArrayOfObjects(events:[Event])->[Event] {
return Array(Set(events.map { $0.eventID! }))
}
Note that the order of the items in a set is undefined, so if you care about the order of the elements, you should try a different solution.

Keep ordered array of dictionary values updated by index

I have a dictionary that's updated from another class. I have a property observer on the dictionary so I know when a value has been added or removed.
I create a sorted array based on the values of the dictionary. I need to keep this array updated and retain the index associated with the update for use with a UITableView. My UI is as such that a wholesale reloading of data isn't possible - I need to directly insert or remove rows based on what the update was.
I have simplified this into a playground:
func dictionaryUpdated() {
print("dictionary updated")
// Add or remove string at index depending on order.
}
var myDictionary : [Int:String] = ["Bob".hashValue:"Bob","Dave".hashValue:"Dave","Yoda".hashValue:"Yoda","Windu".hashValue:"Windu","Obi Wan".hashValue:"Obi Wan","Qui-gon".hashValue:"Qui-gon","Anakin".hashValue:"Anakin"] { didSet { dictionaryUpdated() } }
func addEntry(entry: String) {
myDictionary[entry.hashValue] = entry
}
func removeEntry(entry: String) {
myDictionary.removeValueForKey(entry.hashValue)
}
// sort the keys alphabetically while creating the array
var valuesArray = myDictionary.values.sort { (lhs, rhs) -> Bool in
return lhs < rhs
}
I have tried using an NSMutableOrderedSet but the keys can only be Strings.
Just playing around in playground. Can be much more elegant though...
var valuesArray: [String] = [] { didSet { valuesArray.sortInPlace { $0 < $1 } } }
func dictionaryUpdated(old: [Int: String]) {
let added = myDictionary.count > old.count
let item: [String] = added ? myDictionary.values.filter { !old.values.contains($0) } : old.values.filter { !myDictionary.values.contains($0) }
valuesArray += item
let index = valuesArray.indexOf(item[0])!
print("item " + (added ? "added" : "removed") + ": \(item) at index \(index)")
}
var myDictionary: [Int: String] = ["Yoda".hashValue: "Yoda", "Windu".hashValue: "Windu", "Obi Wan".hashValue: "Obi Wan"] {
didSet {
dictionaryUpdated(oldValue)
}
}
addEntry("Darth Vader")
print(valuesArray)
Output:
item added: ["Darth Vader"] at index 0
["Darth Vader", "Obi Wan", "Windu", "Yoda"]
Assuming you have the sorted array before and after the property change (which can be achieved via another instance variable), what you need to do is to compare the old and the new array, and detect which which indexes changed.
An elegant solution to this problem would be to add a diff method to the Array class which computes the difference. The method might look something like this:
extension Array where Element: Equatable {
func diff(other: [Element]) -> (added: [Int], deleted: [Int], moved: [(from: Int, to: Int)]) {
var added: [Int] = []
var deleted: [Int] = []
var moved: [(from: Int, to: Int)] = []
for (i, item) in enumerate() {
if let j = other.indexOf({$0 == item}) {
if i != j {
moved.append((from: i, to: j))
}
} else {
deleted.append(i)
}
}
for (i, item) in other.enumerate() {
if indexOf({$0 == item}) == nil {
added.append(i)
}
}
return (added: added, deleted: deleted, moved: moved)
}
}
You would then use like this: valuesArray.diff(oldValuesArray).

Set up WatchKit Table

I'm trying to load my data into a WatchKit table. Basically, set the text of the match label in each table group cell with the array of matchs I have.
I've got the data, and everything set up, but actually loading it into the table is where I'm stuck.
InterfaceController.swift:
var receivedData = Array<Dictionary<String, String>>()
var eventsListSO = Array<Event>()
#IBOutlet var rowTable: WKInterfaceTable!
func doTable() {
eventsListSO = Event.eventsListFromValues(receivedData)
rowTable.setNumberOfRows(eventsListSO.count, withRowType: "rows")
for var i = 0; i < self.rowTable.numberOfRows; i++ {
let row = rowTable.rowControllerAtIndex(i) as? TableRowController
for eventm in eventsListSO {
row!.mLabel.setText(eventm.eventMatch)
NSLog("SetupTableM: %#", eventm.eventMatch)
}
}
}
I was trying to do it in doTable because that seemed like best place to do this, and I think doTable is set up right, but I'm not sure? Not sure if I need to make the array an optional type or what.
Here is the referencing code if needed:
RowController.swift:
class TableRowController {
#IBOutlet var mLabel: WKInterfaceLabel!
#IBOutlet var cGroup: WKInterfaceGroup!
}
Event.swift:
class Event {
var eventTColor:String
var eventMatch:String
init(dataDictionary:Dictionary<String,String>) {
eventTColor = dataDictionary["TColor"]!
eventMatch = dataDictionary["Match"]!
}
class func newEvent(dataDictionary:Dictionary<String,String>) -> Event {
return Event(dataDictionary: dataDictionary)
}
class func eventsListFromValues(values: Array<Dictionary<String, String>>) -> Array<Event> {
var array = Array<Event>()
for eventValues in values {
let event = Event(dataDictionary: eventValues)
array.append(event)
}
return array
}
}
So I'm not sure if:
- doTable is set up right (can't be because eventsListSO.count is null)
The way you work with tables in WatchKit is a lot different than UIKit.
After you call setNumberOfRows you need to iterate over each row and get the RowController.
for var i = 0; i < self.rowTable.numberOfRows; i++ {
var row = self.rowTable.rowControllerAtIndex(i)
//setup row here
}
You can check Raywenderlich's tutorial about WatchKit: http://www.raywenderlich.com/96741/watchkit-tutorial-with-swift-tables-glances-and-handoff, it teach you how to show tables on your watch, hope this help!

Resources