Filter an array of objects by distance Kotlin - arrays

Im new to Kotlin and trying to convert some Swift code to Kotlin.
Here is my swift function. It filters out array objects that are over a specific distance from the user.
func filterByDistance(_ events:[Event]) -> [Event] {
let filteredEvents = events.filter { event -> Bool in
if let lat = event.venue?.location?.latitude,
let long = event.venue?.location?.longitude,
let userLocation = UserLocation.shared.location {
let eventLocation = CLLocation(latitude: lat, longitude: long)
let distance = eventLocation.distance(from: userLocation)
let convertedDistance = distance * 0.000621371
if convertedDistance <= maxDistance {
return true
}
}
return false
}
return filteredEvents
}
Below is what I've got so far using Kotlin
fun LatLng.toLocation() = Location(LocationManager.GPS_PROVIDER).also {
it.latitude = latitude
it.longitude = longitude
}
fun filterByDistance(events: Array<Events>): Array<Events> {
val filteredEvents = events.filter<Events> { event ->
val lat = event.venue?.location?.latitude
val long = event.venue?.location?.longitude
val userLocation = LatLng(latitude, longitude)
val eventLocation = LatLng(lat, long)
val distance = eventLocation.toLocation().distanceTo(userLocation.toLocation())
val convertedDistance = distance * 0.000621371
if (convertedDistance <= 500) {
return true
} else {
return false
}
}
return filterEvents(events)
}
Im getting an error asking me to change my return type to a Bool, but I need to return an array of filtered events. Can someone help me out?
EDIT: Thanks to JB Nizet I was able to get this working. I had to change the object from Array to List. Here is the working code.
fun fetchJson() {
val url = "URL String"
val request = Request.Builder().url(url).build()
val client = OkHttpClient()
client.newCall(request).enqueue(object:Callback{
override fun onResponse(call: Call?, response: Response?) {
val body = response?.body()?.string()
val gson = GsonBuilder().create()
val eventss = gson.fromJson(body, Array<Events>::class.java)
val events = eventss.toList()
val filteredEvents = filterByDistance(events)
runOnUiThread {
recyclerView.adapter = MainAdaptor(filteredEvents)
}
}
override fun onFailure(call: Call?, e: IOException?) {
println("failed")
}
})
}
fun LatLng.toLocation() = Location(LocationManager.GPS_PROVIDER).also {
it.latitude = latitude
it.longitude = longitude
}
fun filterByDistance(events: List<Events>): List<Events> {
val filteredEvents = events.filter { event ->
val lat = event.venue?.location?.latitude
val long = event.venue?.location?.longitude
val userLocation = LatLng(latitude, longitude)
val eventLocation = LatLng(lat, long)
val distance = eventLocation.toLocation().distanceTo(userLocation.toLocation())
val convertedDistance = distance * 0.000621371
convertedDistance <= maxDistance
}
return filteredEvents
}
And the Class if it helps anyone:
class Events (val type: String,
val venue: Venue,
val time: String,
val name: String,
val summary: String,
val activity: String,
val image_link: String,
val membership_link: String,
val description: String
)
class Venue(val type: String,
val name: String,
val address: String,
val location:Location
)
class Location(val type: String,
val latitude: Double,
val longitude: Double)

Replace
if (convertedDistance <= 500) {
return true
} else {
return false
}
by
convertedDistance <= 500
and
return filterEvents(events)
by
return filteredEvents
See https://kotlinlang.org/docs/reference/lambdas.html#lambda-expression-syntax for an explanation of the lambda syntax:
We can explicitly return a value from the lambda using the qualified return syntax. Otherwise, the value of the last expression is implicitly returned. Therefore, the two following snippets are equivalent:
ints.filter {
val shouldFilter = it > 0
shouldFilter
}
ints.filter {
val shouldFilter = it > 0
return#filter shouldFilter
}

Related

How can I merge 2 dictionaries into one array?

My JSON data look like this image below. Now I wanna merge the value of Shop Type and Promotion into one to use as collection view data. How can I do that?
I just filter the response data from the server like this:
var dataBanDau: [SDFilterModel] = []
var quickData: [SDFilterModel] = []
let filters: [SDFilterModel] = data
self.filterEntries = filters
//let nsarray = NSArray(array: self.filterEntries! , copyItems: true)
// self.filterEntriesStoreConstant = nsarray as! Array
self.dataBanDau = filters
for i in 0..<self.dataBanDau.count {
if self.dataBanDau[i].search_key.count == 0 {
self.quickData.append(self.dataBanDau[i])
}
}
self.quickData = self.quickData.filter {
$0.type != "range"
}
DispatchQueue.main.async {
//Note: Reload TableView
self.quickFilterCollection.reloadData()
completed(true)
}
}
the class SDFilterModel:
class SDFilterModel: DSBaseModel {
var name = String()
var type = String()
var is_expanded = Int()
var search_key = String()
var filterEntries : [SDFilterModel]?
override func copy(with zone: NSZone? = nil) -> Any {
// This is the reason why `init(_ model: GameModel)`
// must be required, because `GameModel` is not `final`.
let copy = SDFilterModel(dict: self.dictionary)
if let arrAttribute = NSArray(array: self.value , copyItems: true) as? [AttributeValueModel] {
copy.value = arrAttribute
}
return copy
}
override init(dict: Dictionary<String, Any>) {
super.init(dict: dict);
value = self.valueParse()
name = dict.getString(forKey: "name")
type = dict.getString(forKey: "type")
search_key = dict.getString(forKey: "search_key")
is_expanded = dict.getInt(forKey: "is_expanded")!
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
var value: [AttributeValueModel] = [];
func valueParse()-> [AttributeValueModel] {
guard let childs = (self.dictionary["value"]) as? [Dictionary<String, AnyObject>]
else { return [] }
var output: [AttributeValueModel] = [];
for aDict in childs {
let item = AttributeValueModel(dict:aDict);
// if type == .Range && item.option_id == "0" {
// item.setRangeOptionID(aValue: item.option_name!)
// }
//
output.append(item);
}
return output;
}
Let be Assume you have let myArray = [1,2,3,4,5,6,7,8]
Now you wanted to square of each and every element in the array,
With for loop you do like this
for item in myArray {
print(item * item)
}
Now assume item = $0
With for map you jus do
myArray.map({ $0 * $0 })
Both will gave same output.
map : Use to do same operation on every element of array.
flatmap : It is used to flattern the array of array.
let myArr = [[1,2,3],[4,5,6,7]]
and you want o/p as [1,2,3,4,5,6,7]
So can get above output with myArr.flatMap({$0})
Now back to your question.
let reqArray = myModel.data.map({ $0.value }).flatMap({ $0 })
First, map gaves you array-of-array of key value but you need a single array, so for that you need to use flatmap.
You can take ref : https://medium.com/#Dougly/higher-order-functions-in-swift-sorted-map-filter-reduce-dff60b5b6adf
Create the models like this
struct Option {
let name: String
let searchKey: String
let id: String
}
struct Model {
let type: String
let name: String
let isExpanded: Bool
let value: [Option]
}
You should get the options array values and join all the arrays
let models:[Model] = //...
let collectionViewArray = models.map { $0.value }.reduce([Option](), +)
Using for loop
var collectionViewArray = [Option]()
for model in models {
collectionViewArray.append(contentsOf: model.value)
}

Transforming a JSONObject to JSONArray in Kotlin

Kotlin code
private fun loadRecyclerViewData() {
val request = Request.Builder().url(URL_Json).build()
val client = OkHttpClient()
client.newCall(request).enqueue(object: Callback{
override fun onResponse(call: Call?, response: Response?) {
jsonData = response?.body()?.string()
data class Info( val id: Int, val type: Int, val message: String, val typefield: Any, val hidden: Boolean,
val topSpacing: Int, val show: Any, val required: Boolean)
//val gson = GsonBuilder().create()
val gson = Gson()
val persons = gson.fromJson(jsonData, Info::class.java)
println("mensagem "+ jsonData) //return jsonObject
println("mensagem "+ persons) //return null
runOnUiThread {
//recyclerView?.adapter = FieldAdapter(feed)
}
}
override fun onFailure(call: Call?, e: IOException?) {
println("Fail request")
}
})
}
JSON link:
https://floating-mountain-50292.herokuapp.com/cells.json
Hi guys.
I need some help with Kotlin. I want to transform a JSONObjetct into JSONArray. But I have return = null.
can you help me?
First Println return JSONObject ok, but second println return null.
println 1
https://imgur.com/Ww2bvAv
println 2
https://imgur.com/eViUe8q

Appending Array Inside Function

I am trying to append values to an array inside a function and call that updated array in another function but it is not printing the new appended values.
I am using firebase and getting a snapshot of the database, sorting it, finding value of keys, and appending to hDates
var hDates:Array = [""]
getHistoryPGE() { hDates in
print(hDates)
self.hDates = [hDates]
}
func getHistoryPGE(completion: #escaping (String)->()) {
let userID = Auth.auth().currentUser?.uid
let ref = Database.database().reference().child("users").child(userID!)
ref.child("PostGameEval").observe(.value, with: { (snapshot) in
if let dict = snapshot.value as? [String : [String: [String: Any]]] {
let keys = Array(dict.keys)
var num : Int = 7
for i in 0..<keys.count {
if let innerDict = dict[keys[i]] {
let innerKeys = Array((innerDict).keys)
let sortedInnerKeys = innerKeys.sorted(by: { $0 > $1} )
while (sortedInnerKeys.count < num){
num -= 1
}
for j in 0..<num {
if let tempDict = innerDict[sortedInnerKeys[j]] {
print(tempDict["1abA"] as! String)
}
}
}
}
}})
}
func calendar(_ calendar: FSCalendar, numberOfEventsFor date: Date) -> Int {
let dateString = self.dateFormatter.string(from: date)
if self.hDates.contains(dateString) {
return 1
}
return 0
}

How would I go about categorizing items within an Array in swift?

In swift, I want to categorize items in an existing array and place them accordingly in one new string.
Here is an example of what I want to do:
originalArray = ["hotdog","fries","hotdog","coke","coke","fries","hotdog"]
resultingString = "hotdog x 3, fries x 2, coke x 2"
How would I go about doing this?
Try this:
let originalArray = ["hotdog","fries","hotdog","coke","coke","fries","hotdog"]
var dict = [String: Int]()
let resultString = originalArray.reduce(dict) { _, element in
if dict[element] == nil {
dict[element] = 1
} else {
dict[element]! += 1
}
return dict
}
.map { "\($0) x \($1)" }
.joinWithSeparator(", ")
If you want to keep the original order of the array (ie: hotdog, fries, coke), the code is slightly more complicated:
let originalArray = ["hotdog","fries","hotdog","coke","coke","fries","hotdog"]
var dict = [String: (index: Int, count: Int)]()
let resultString = originalArray.enumerate()
.reduce(dict) { _ , e in
if let value = dict[e.element] {
dict[e.element] = (index: value.index, count: value.count + 1)
} else {
dict[e.element] = (index: e.index, count: 1)
}
return dict
}
.sort { return $0.1.index < $1.1.index }
.map { "\($0) x \($1.count)" }
.joinWithSeparator(", ")
print(resultString)
I think this will help you:
let originalArray = ["hotdog","fries","hotdog","coke","coke","fries","hotdog"]
var resultingString = ""
var counts:[String:Int] = [:]
for item in originalArray {
counts[item] = (counts[item] ?? 0) + 1
}
resultingString = counts.map { (key, value) -> String in
return "\(key) x \(value)"
}.joinWithSeparator(",")
print(resultingString)
Here is the output: coke x 2, hotdog x 3, fries x 2

Need help accessing second layer of data in an API call in Swift 2

I am using the following line of code to access "intent", but I need to access the "Value" within "from" (e.g. london). What am I doing wrong?
My original code:
func witDidGraspIntent(outcomes: [AnyObject]!, messageId: String!, customData: AnyObject!, error e: NSError!) {
if ((e) != nil) {
print("\(e.localizedDescription)")
return
}
let outcomes : NSArray = outcomes!
let firstOutcome : NSDictionary = outcomes.objectAtIndex(0) as! NSDictionary
let intent : String = firstOutcome.objectForKey("intent")as! String
let query : String = firstOutcome.objectForKey("from":["value"])as! String
The API data structure is as follows:
{
"_text" = "show me flights from london to turkey";
confidence = "0.536";
entities = {
from = (
{
suggested = 1;
type = value;
value = london;
}
);
productCategory = (
{
type = value;
value = flights;
}
);
to = (
{
suggested = 1;
type = value;
value = turkey;
}
);
};
intent = flightSearch;
metadata = "";
}
thanks!
Here is an example of how you'd pull values out of a NSDictionary using Key-Value Coding
import Foundation
let outcomeData = "{ \"_text\" = \"show me flights from london to turkey\"; confidence = \"0.536\"; entities = { from = ( { suggested = 1; type = value; value = london; } ); productCategory = ( { type = value; value = flights; } ); to = ( { suggested = 1; type = value; value = turkey; } ); }; intent = flightSearch; metadata = \"\"; }".propertyList()
// Safely cast as NSDictionary
if let outcome = outcomeData as? NSDictionary {
// Safely get the value from a key and cast as String
if let intent = outcome.valueForKey("intent") as? String {
print(intent) // => "flightSearch"
}
// Safely get the value from a key path and cast as a String
if let query = outcome.valueForKeyPath("entities.from.value.#firstObject") as? String{
print(query) // => "london"
}
}
Avoid explicitly-unwrapped Optional and forced unwrapping of Optional wherever possible. You're asking for lots of trouble down the line using them.

Resources