How can i shuffle RLMResults in swift? - ios

Any idea how can i shuffle randomly for RLMResults? I couldn't find anyway to do it via RLMSortDescriptor.
I tried writing my own swap algorithm, but it's giving me error (cannot assign to results of this expression*).
func simpleRandomSwap(rlmobjects:RLMResults!) -> RLMResults! {
if (rlmobjects != nil && rlmobjects.count > 0) {
let indexcount = Int(rlmobjects.count)
for (var i=0 ; i<indexcount; i++) {
let randomUInt:UInt = UInt(arc4random_uniform(UInt32(indexcount)))
let myuint = UInt(i)
// simple swap
var temp = rlmobjects.objectAtIndex(myuint)
rlmobjects.objectAtIndex(randomUInt) = rlmobjects.objectAtIndex(myuint)
rlmobjects.objectAtIndex(myuint) = temp
} // end for loop
}
return rlmobjects
}

First a quick note: RLMResults have no defined order unless they are sorted via RLMSortDescriptor.
Instead, to randomly sort you have two options:
Add a integer property to your object schema and assign random values to all the objects. You can then use a RLMSortDescriptor with RLMResults to sort the objects.
As mentioned in the comments above, copy the RLMObjects into an array and perform a random sort on this.
Here is an extension to RLMObject that does this:
extension RLMResults {
public func toShuffledArray<T>(ofType: T.Type) -> [T] {
var array = [T]()
for result in self {
if let result = result as? T {
array.append(result)
}
}
let count = array.count
if count > 1 {
for i in 0..<(count - 1) {
let j = Int(arc4random_uniform(UInt32(count - i))) + Int(i)
swap(&array[i], &array[j])
}
}
return array
}
}
You would call it like this:
let shuffled = results.toShuffledArray(TestObject.self)

Swift 5:
You can just use default method:
let shuffled = results.shuffled()

Related

Any magic command to extract an array from array of custom objects?

I have a class like this
class ValueTimestamp {
let value: Double
let timestamp : Double
init(value:Double, timestamp:Double) {
self.value = valuer
self.timestamp = timestamp
}
}
Then I have an array filled with ValueTimestamp objects. Let's call this, myArray.
Now I want to manipulate the array, to extract, for example the elements with values bigger than 10.
Because I am new to swift, I would do this:
// this will create an array with Doubles
let sub = myArray.map($0.value > 10)
var newArray : [ValueTimestamp] = []
for i in 0..< myArray.count {
let newValue = ValueTimestamp.init(value:sub[i], timestamp:myArray[i])
newArray.append(newValue)
}
and now I have newArray that contains the elements from myArray with values bigger than 10.
Is there any magic command using .map, .flatmap or whatever that can do this?
What you looking for is filter method:
public func filter(_ isIncluded: (Element) throws -> Bool) rethrows -> [Element]
It takes as parameter closure, which take 1 element and return true if element should be added in resulting array or false if it should be filtered out.
Your code:
let biggerThem10 = myArray.filter { $0.value > 10 }

How can I filter a single category in UICollectionView in swift?

I'm new in swift and I have some problem while I try to filter some categories in my UICollectionView.
Here my code to get all articles for all the categories.
func getArticlesforCategory(category: String) -> Int {
var result : Int = 0
for article in self.allArticles {
if category == article.category {
result += 1
}
}
return result
}
How can I filter only one single category, for example "test"?
I get all the categories by parsing xml from wordpress website
You can use filter function to filter your array :
func getArticlesforCategory(category: String) -> Int {
let filteredArray = allArticles.filter( {$0.category == category }) // Here you have filtered array
return filteredArray.count // If you want number of items pass count of filtered array
}
try below line:
let result = self.allArticles.filter { $0.category == "test" }.count
You can use filter, try this code
func getFilteredArray(category: String) -> [ array of your objects] {
let filteredArray = allArticles.filter( {$0.category == category })
return filteredArray
}

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).

Compare two list of images and filter out repetition. (Swift)(iOS)

I have two lists of IDs (strings) which represent two sets of images.
The viewSpaceArray are the IDs of the images already viewed by users.
HomeViewData contains the entire collection of images.
The currentSpaceId is the IDs of the current image.
Number is the index of the items on HomeViewData
What I want to do is to filter out viewed image until I get an "unviewed" one.
I managed to compare a single currentSpaceId to the list viewSpaceArray, but I don't know how to create a loop to go through a series of currentSpaceId until I find an unviewed item. Here is the code:
Thanks
func filterViewedSpaces() {
viewedSpaceArray.removeAllObjects()
var findViewQuery:PFQuery = PFQuery(className: "views")
findViewQuery.findObjectsInBackgroundWithBlock{
(objects: [AnyObject]!, error:NSError!) -> Void in
if error == nil {
for object in objects {
let upload:PFObject = object as PFObject
let spaceId = upload["spaceId"] as String
self.viewedSpaceArray.addObject(spaceId)
}
}
}
var currentSpace:PFObject = self.homeViewData[self.number] as PFObject
var currentSpaceId = currentSpace.objectId as String!
for object in viewedSpaceArray {
let vSpaceId = object as String
if currentSpaceId == vSpaceId {
number++
} else {
loadData()
}
}
}
Here is one way using the set difference algorithm found here:
/// Computes the relative complement of a with respect to b
func relative_complement<T: Comparable>(a a0: Array<T>, b b0: Array<T>) -> Array<T> {
let a = a0.sorted { $0 < $1 }
let b = b0.sorted { $0 < $1 }
var result = [T]()
var x = 0, y = 0
while x < a.count {
if y == b.count {
return Array<T>(a[x..<a.count])
}
if a[x] < b[y] {
result.append(a[x])
++x
}
else {
if !(b[y] < a[x]) {
++x
}
++y
}
}
return result
}
You can use it like this:
let collection = ["a","b","c","d","e","f"]
let viewed = ["a","c","d","f"]
let relcomp = relative_complement(a: collection, b: viewed)
// relcomp contains ["b","e"]

Resources