I am trying to convert Java code into Swift. I have gone so far but stuck into custom comparator logic. I am wondering how to achieve that in Swift.
class CustomItem {
var start: Int
var end: Int
init(start: Int, end: Int) {
self.start = start
self.end = end
}
static func compare_customs(_ content: [UInt8], _ custom1: CustomItem , _ custom2 : CustomItem) -> Int {
// the logic is implemented here already!
}
}
var content: [UInt8] = output.getBuffer()
var items = [CustomItem]()
for i in 0..<offsets.count - 1 {
items[i] = CustomItem(start: offsets[i], end: offsets[i + 1])
}
items[offsets.count - 1] = CustomItem(start: offsets[offsets.count - 1], end: output.size())
// Swift Custom comparator logic here??
Trying to convert the following Java custom comparator logic into Swift. Any guidance would be appreaciated.
byte[] content = output.getBuffer();
java.util.Arrays.sort(items, new java.util.Comparator<CustomItem>() {
#Override
public int compare(CustomItem custom1, CustomItem custom2) {
return CustomItem.compare_customs(content, custom1, custom2);
}
});
It would be something like
items.sort { CustomItem.compare_customs(content, $0, $1) < 0 }
Related
Hey guys I switched from Swift to Kotlin a few days ago and I'm trying to implement a similar function I have in swift into kotlin and failing
Here is what I'm doing in swift
private var issues: [PathPmCore.Issue] = [] {
didSet {
AppState.shared.issues = issues
taskModels.removeAll()
var models = [ListModel]()
var components = [Double]()
for status in TaskState.allCases {
let count = issues.filter({ isssue in
status.ids.contains(where: { statusId in
statusId == isssue.status.currentStatus.id
})
}).count
models.append(.init(activeTasks: .constant(count), circleState: .constant(status)))
components.append(Double(count))
}
DispatchQueue.main.async {
self.taskModels = models
self.chartComponents = components
}
}
The way I approached it in Kotlin is similar
private var issues: List<Issues> = emptyList()
set(value: List<Issues>){
for (status in TaskState.values()) {
val models: ArrayList<ListModel> = arrayListOf<ListModel>()
val components = listOf<Double>()
val count = issues.filterNotNull().forEach { issue ->
status.ids.find { statusId ->
statusId == issue.status.currentStatus.id
}
}
println(count)
value.count()
}
}
It works, with no errors but the one setter in Kotlin returns an empty array/list.
Why it's empty
It's empty because you are not setting the backing field !
Possible Solution (maybe)
So, if I understood right what you are trying to achieve, here is a possible solution for your problem
private var issues: List<Issues> = emptyList()
set(value: List<Issues>){
field = TaskState.values().map {
issues.filterNotNull().filter { issue ->
it.ids.any { statusId ->
statusId == issue.status.currentStatus.id
}
}
}.flatten()
}
I removed models and components because you are not using them.
how can i frame Flow<ByteString, ByteString, NotUsed> by size? All examples I have found assumes that there is some delimiter, which is not my case, I just need to frame by length / size.
Framing via Framing.delimiter does require a designated delimiter, and there doesn't seem to be any built-in stream operator that does framing simply by a fixed chunk size. One of the challenges in coming up with a custom framing/chunking solution is to properly handle the last chunk of elements.
One solution would be to assemble a custom GraphStage like the "chunking" example illustrated in the Akka Stream-cookbook:
import akka.stream.stage.{GraphStage, GraphStageLogic, InHandler, OutHandler}
import akka.stream.{Attributes, Inlet, Outlet, FlowShape}
import akka.util.ByteString
class Chunking(val chunkSize: Int) extends GraphStage[FlowShape[ByteString, ByteString]] {
val in = Inlet[ByteString]("Chunking.in")
val out = Outlet[ByteString]("Chunking.out")
override val shape = FlowShape.of(in, out)
override def createLogic(inheritedAttributes: Attributes): GraphStageLogic = new GraphStageLogic(shape) {
private var buffer = ByteString.empty
setHandler(in, new InHandler {
override def onPush(): Unit = {
val elem = grab(in)
buffer ++= elem
emitChunk()
}
override def onUpstreamFinish(): Unit = {
if (buffer.isEmpty)
completeStage()
else {
if (isAvailable(out)) emitChunk()
}
}
})
setHandler(out, new OutHandler {
override def onPull(): Unit = {
if (isClosed(in)) emitChunk()
else pull(in)
}
})
private def emitChunk(): Unit = {
if (buffer.isEmpty) {
if (isClosed(in)) completeStage() else pull(in)
}
else {
val (chunk, nextBuffer) = buffer.splitAt(chunkSize)
buffer = nextBuffer
push(out, chunk)
}
}
}
}
Note that emitChunk() handles the fixed-size chunking and onUpstreamFinish() is necessary for processing the last chunk of elements in the internal buffer.
Test-running with a sample text file "/path/to/file" which has content as below:
Millions of people worldwide are in for a disastrous future of hunger, drought and disease, according to a draft report from the United Nations' Intergovernmental Panel on Climate Change, which was leaked to the media this week.
import akka.actor.ActorSystem
import akka.stream.scaladsl._
import java.nio.file.Paths
implicit val system = ActorSystem("system")
implicit val executionContext = system.dispatcher
val chunkSize = 32
FileIO.fromPath(Paths.get("/path/to/file")).
via(new Chunking(chunkSize)).
map(_.utf8String).
runWith(Sink.seq)
// res1: scala.concurrent.Future[Seq[String]] = Future(Success(Vector(
// "Millions of people worldwide are",
// " in for a disastrous future of h",
// "unger, drought and disease, acco",
// "rding to a draft report from the",
// " United Nations' Intergovernment",
// "al Panel on Climate Change, whic",
// "h was leaked to the media this w",
// "eek."
// )))
Something like (in Scala, disclaimer: only mentally compiled) this, using statefulMapConcat, which allows
emitting zero or more frames per input element
maintaining state from element to element of what's yet to be emitted
val frameSize: Int = ???
require(frameSize > 0, "frame size must be positive")
Flow[ByteString].statefulMapConcat { () =>
var carry: ByteString = ByteString.empty
{ in =>
val len = carry.length + in.length
if (len < frameSize) {
// append to carry and emit nothing
carry = carry ++ in
Nil
} else if (len == frameSize) {
if (carry.nonEmpty) {
carry = ByteString.empty
List(carry ++ in)
} else List(in)
} else {
if (carry.isEmpty) {
val frames = len / frameSize
val (emit, suffix) = in.splitAt(frames * frameSize)
carry = suffix
emit.grouped(frameSize)
} else {
val (appendToCarry, inn) = in.splitAt(frameSize - carry.length)
val first = carry ++ appendToCarry
val frames = inn.length / frameSize
if (frames > 0) {
val (emit, suffix) = inn.splitAt(frames * frameSize)
carry = suffix
Iterator.single(first) ++ emit.grouped(frameSize)
} else {
carry = inn
List(first)
}
}
}
}
If in Java, note that carry ++ in can be expressed as carry.concat(in). It may be useful, in order to get around the restriction in Java around closing over non-final variables, to use a 1-element ByteString[] (e.g. ByteString[] carry = { ByteString.empty }).
I'm converting a Kotlin based Android app into a Java based one. But got a problem with several Kotlin's methods, especially with the arrayListOf(), sortedWith(), compareBy() methods. The converting tools from Android Studio gave even more confusing result.
The method in Kotlin:
fun getSupportedVideoSize(mediaCodec: MediaCodec, mime: String, preferredResolution: Size): Size {
if (mediaCodec.codecInfo.getCapabilitiesForType(mime)
.videoCapabilities.isSizeSupported(preferredResolution.width, preferredResolution.height))
return preferredResolution
val resolutions = arrayListOf(
Size(176, 144),
Size(320, 240),
Size(320, 180),
Size(640, 360),
Size(720, 480),
Size(1280, 720),
Size(1920, 1080)
)
val pix = preferredResolution.width * preferredResolution.height
val preferredAspect = preferredResolution.width.toFloat() / preferredResolution.height.toFloat()
val nearestToFurthest = resolutions.sortedWith(compareBy(
{
pix - it.width * it.height
},
{
val aspect = if (it.width < it.height) it.width.toFloat() / it.height.toFloat()
else it.height.toFloat()/it.width.toFloat()
(preferredAspect - aspect).absoluteValue
}))
for (size in nearestToFurthest) {
if (mediaCodec.codecInfo.getCapabilitiesForType(mime).videoCapabilities.isSizeSupported(size.width, size.height))
return size
}
throw RuntimeException("Couldn't find supported resolution")
}
Converted method in Java:
public static Size getSupportedVideoSize(MediaCodec mediaCodec, String mime, Size preferredResolution) {
if (mediaCodec.getCodecInfo().getCapabilitiesForType(mime).getVideoCapabilities().isSizeSupported(preferredResolution.getWidth(), preferredResolution.getHeight())) {
return preferredResolution;
} else {
ArrayList<Size> resolutions = new ArrayList<>();
final int pix = preferredResolution.getWidth() * preferredResolution.getHeight();
final float preferredAspect = (float)preferredResolution.getWidth() / (float)preferredResolution.getHeight();
}
for (nearestToFurthest: Size size) {
if (mediaCodec.getCodecInfo().getCapabilitiesForType(mime).getVideoCapabilities().isSizeSupported(size.width, size.height)) {
return size;
}
}
}
I don't know Kotlin but I assume these would be equivalent:
arrayListOf --> List.of
(this is unmodiafiable list, if you really want arraylist, use new ArrayList<>(Arrays.asList(...)) )
sortedWith(compareBy(...)) --> sort([Comparator or lambda expression])
I have string like this.
val input = "perm1|0,perm2|2,perm2|1"
Desired output type is
val output: Set<String, Set<Long>>
and desired output value is
{perm1 [], perm2 [1,2] }
Here I need empty set if value is 0. I am using groupByTo like this
val output = input.split(",")
.map { it.split("|") }
.groupByTo(
mutableMapOf(),
keySelector = { it[0] },
valueTransform = { it[1].toLong() }
)
However the output structure is like this
MutableMap<String, MutableList<Long>>
and output is
{perm1 [0], perm2 [1,2] }
I am looking for best way to get desired output without using imperative style like this.
val output = mutableMapOf<String, Set<Long>>()
input.split(",").forEach {
val t = it.split("|")
if (t[1].contentEquals("0")) {
output[t[0]] = mutableSetOf()
}
if (output.containsKey(t[0]) && !t[1].contentEquals("0")) {
output[t[0]] = output[t[0]]!! + t[1].toLong()
}
if (!output.containsKey(t[0]) && !t[1].contentEquals("0")) {
output[t[0]] = mutableSetOf()
output[t[0]] = output[t[0]]!! + t[1].toLong()
}
}
You can simply use mapValues to convert values type from List<Long> to Set<Long>
var res : Map<String, Set<Long>> = input.split(",")
.map { it.split("|") }
.groupBy( {it[0]}, {it[1].toLong()} )
.mapValues { it.value.toSet() }
And of you want to replace list of 0 with empty set you can do it using if-expression
var res : Map<String, Set<Long>> = input.split(",")
.map { it.split("|") }
.groupBy( {it[0]}, {it[1].toLong()} )
.mapValues { if(it.value == listOf<Long>(0)) setOf() else it.value.toSet() }
Note that you cannot have Set with key-value pair, result will be of type map. Below code gives sorted set in the values.
val result = "perm1|0,perm2|2,perm2|1".split(",")
.map {
val split = it.split("|")
split[0] to split[1].toLong()
}.groupBy({ it.first }, { it.second })
.mapValues { it.value.toSortedSet() }
While the other answer(s) might be easier to grasp, they build immediate lists and maps in between, that are basically discarded right after the next operation. The following tries to omit that using splitToSequence (Sequences) and groupingBy (see Grouping bottom part):
val result: Map<String, Set<Long>> = input.splitToSequence(',')
.map { it.split('|', limit = 2) }
.groupingBy { it[0] }
.fold({ _, _ -> mutableSetOf<Long>() }) { _, accumulator, element ->
accumulator.also {
it.add(element[1].toLong()))
}
}
You can of course also filter out the addition of 0 in the set with a simple condition in the fold-step:
// alternative fold skipping 0-values, but keeping keys
.fold({ _, _ -> mutableSetOf<Long>() }) { _, accumulator, element ->
accumulator.also {
val value = element[1].toLong()
if (value != 0L)
it.add(value)
}
}
Alternatively also aggregating might be ok, but then your result-variable needs to change to Map<String, MutableSet<Long>>:
val result: Map<String, MutableSet<Long>> = // ...
.aggregate { _, accumulator, element, first ->
(if (first) mutableSetOf<Long>() else accumulator!!).also {
val value = element[1].toLong()
if (value != 0L)
it.add(value)
}
}
I'm making an iOS app that parses JSON data from a google spreadsheet. One of the issues with Google JSON data is that it includes unnecessary data that has to be removed. I'm new to iOS programming.
/*O_o*/google.visualization.Query.setResponse({"version":"0.6","reqId":"0","status":"ok","sig":"1400846503","table":{JSON DATA I NEED}});
I have done this in JAVA on Android using this code
int start = result.indexOf("{", result.indexOf("{") + 1);
int end = result.lastIndexOf("}");
String jsonResponse = result.substring(start, end);
My swift code
var something = "My google JSON Data"
let Start = String(something).characters.indexOf("{")!;
let substring1: String = something.substringFromIndex(Start);
something = substring1;
let End = String(something).characters.indexOf(")")!.distanceTo(something.endIndex);
let index3 = something.endIndex.advancedBy(-End);
let substring4: String = something.substringToIndex(index3)
What I'm asking is how do I get the index of the 2nd "{"
You should use NSJsonSerializer, but if you want to do it your way:
extension String {
func indexOf(target: String) -> Int {
if let range = self.rangeOfString(target) {
return self.startIndex.distanceTo(range.startIndex)
} else {
return -1
}
}
func indexOf(target: String, startIndex: Int) -> Int {
let startRange = self.startIndex.advancedBy(startIndex)
if let range = self.rangeOfString(target, options: .LiteralSearch, range: startRange..<self.endIndex) {
return self.startIndex.distanceTo(range.startIndex)
} else {
return -1
}
}
}
let end = myString.indexOf("{", startIndex: myString.indexOf("{") + 1)