I get rows from database into array. And then for example I have in these rows fields like ´ID´,´Section´. Is it possible to get all ID´s for chosen section from array without loops using some operators?
For Instance
1 a
2 b
2 a
3 a
4 b
and then for section 'a' I'd like to get [1,2,3]
If your database is an Array of Tuples you can do something like this:
let database: [(Int, String)] = [(1, "a"), (2, "b"), (2, "a"), (3, "a"), (4, "b")]
let aNumbers = database.filter{ $0.1 == "a" }.map{ $0.0 }
Or with swift 2:
let aNumbers = database.flatMap{ $0.1 == "a" ? $0.0 : nil }
Related
I have the following data class:
data class Foo(val a: Int = 0, val b: Int = 0)
I have a list of Foo's with the following structure:
[ Foo(a = 1), Foo(a = 2), ..., Foo(b = 22), Foo(a = 5), Foo(a = 6), ... ]
(a group of items with a's, then one b, then a's again)
I would like to split above list into three sub-lists like that:
[ Foo(a = 1), Foo(a = 2), ...]
[ Foo(b = 22) ]
[ Foo(a = 5), Foo(a = 6), ...]
sublist of elements that have non-zero a property
list of one element that has non-zero b
remaining sublist of elements that have non-zero a property
Is it possible to achieve using groupBy or partition?
It is not possible to do it via groupBy or partition, because it is not possible to check the past state in those operations. However, you can do it via a fold operation and using mutable lists. Not sure if it fits to your needs but here it goes:
val input = listOf(Foo(a = 1), Foo(a = 2), Foo(b = 22), Foo(a = 5), Foo(a = 6))
val output: List<List<Foo>> = input.fold(mutableListOf<MutableList<Foo>>(mutableListOf())) { acc, foo ->
val lastList = acc.last()
val appendToTheLastList =
lastList.isEmpty() ||
(foo.a != 0 && lastList.last().a != 0) ||
(foo.b != 0 && lastList.last().b != 0)
when {
appendToTheLastList -> lastList.add(foo)
else -> acc.add(mutableListOf(foo))
}
return#fold acc
}
println(output)
outputs:
[[Foo(a=1, b=0), Foo(a=2, b=0)], [Foo(a=0, b=22)], [Foo(a=5, b=0),
Foo(a=6, b=0)]]
Note: I have to point out that this solution is not better than a solution with regular loops.
So you want to 1) ignore the first Foos where a=0, 2) start collecting them when you see Foos where a is non-zero, 3) when you hit a Foo where a=0, put that in another list, because b will be non-zero, 4) start collecting non-zero a's again in a third list?
If that's what you want (this is an extremely specific thing you want and you haven't been clear about it at all) you could do it this way:
data class Foo(val a: Int, val b: Int)
val stuff = listOf(Foo(0,1), Foo(1,2), Foo(3,0), Foo(0, 4), Foo(0, 5), Foo(6, 1), Foo(0,7))
fun main(args: Array<String>) {
fun aIsZero(foo: Foo) = foo.a == 0
// ignore initial zero a's if there are any
with(stuff.dropWhile(::aIsZero)) {
val bIndex = indexOfFirst(::aIsZero)
val listOne = take(bIndex)
val listTwo = listOf(elementAt(bIndex))
val listThree = drop(bIndex+1).filterNot(::aIsZero)
listOf(listOne, listTwo, listThree).forEach(::println)
}
}
You can't use partition or groupBy because your predicate depends on the value of a, but also on whether it happens to represent that one element you want to put in the b list, and for the others whether they appear before or after that b element. Which you don't know before you start processing the list.
You could mess around with indices and stuff, but honestly your use case seems so specific that it's probably better to just do it imperatively instead of trying to cram it into a functional approach.
Assuming we are given a list of integers R = [3,5,3,6,0,6,7], an threshold x (integer) and a window size (integer) p. For example, x=4 and p = 2.
I need to find the first index t that verifies the the following conditions:
R[t] >= 4, R[t+1] >= 4. Since p=2, we need to only verify for two boxes t and t+1. If p was equal to 3 we will need to verify for t, t+1 and t+2.
Here the t I am looking for is 5 (indexing is starting from 0).
How to write this in a elegant way in Kotlin (rather than looping on the elements).
A tentative that is giving an error (x=4 and p = 2. The output should be 3 since we start indexing by 0):
val numbers = listOf(1, 2, 3, 4, 6, 8, 2)
val firstIndex = numbers.find { it >= 4 for it in it..it+2-1}
val numbers = listOf(1, 2, 3, 4, 6, 8, 2)
val p = 2
val x = 4
val t = numbers.windowed(p).indexOfFirst { window -> window.all { it >= x } } // t == 3
t will be equal to -1 in case if no matches will be found
Use windowed to check groups of values for each index in the list. Use withIndex() so you are iterating with the indices, which you need in your final result. Then use firstOrNull() (which find() is a redundant alias of). And finally, take ?.index to get the index of the first entry that satisfies the condition, or null if none satisfy.
val x = 4
val p = 3
val list = listOf(2,5,3,6,0,6,7)
val t = list
.windowed(p)
.withIndex()
.firstOrNull { (_, sublist) -> sublist.all { it >= x } }
?.index
find Returns the first element matching the given predicate, or null if no such element was found.
If I've understood correctly, this should work:
fun main() {
val list = listOf(3,5,3,6,0,6,7)
val p = 2
val x = 4
val t = list.withIndex().windowed(p).firstOrNull() { window ->
window.all { it.value >= x }
}?.first()?.index
println(t)
}
Output:
5
For an array with a non-one based index like:
using OffsetArrays
a = OffsetArray( [1,2,3], -1)
Is there a simple way to get a tuple of (index,value), similar to enumerate?
Enumerating still counts the elements... collect(enumerate(a)) returns:
3-element Array{Tuple{Int64,Int64},1}:
(1, 1)
(2, 2)
(3, 3)
I'm looking for:
(0, 1)
(1, 2)
(2, 3)
The canonical solution is to use pairs:
julia> a = OffsetArray( [1,2,3], -1);
julia> for (i, x) in pairs(a)
println("a[", i, "]: ", x)
end
a[0]: 1
a[1]: 2
a[2]: 3
julia> b = [1,2,3];
julia> for (i, x) in pairs(b)
println("b[", i, "]: ", x)
end
b[1]: 1
b[2]: 2
b[3]: 3
It works for other types of collections too:
julia> d = Dict(:a => 1, :b => 2, :c => 3);
julia> for (i, x) in pairs(d)
println("d[:", i, "]: ", x)
end
d[:a]: 1
d[:b]: 2
d[:c]: 3
You can find a lot of other interesting iterators by reading the documentation of Base.Iterators.
Try eachindex(a) to get the indexes, see the example below:
julia> tuple.(eachindex(a),a)
3-element OffsetArray(::Array{Tuple{Int64,Int64},1}, 0:2) with eltype Tuple{Int64,Int64} with indices 0:2:
(0, 1)
(1, 2)
(2, 3)
I am in a need to compare 2 JSON objects where the order has retained while comparing. As Karate match ignores the order of an element, I am just curious to know if there is a way to do so in Karate.
Not directly, it is never needed, since JSON keys can be in any order, like a Map.
But you can do an exact match after converting to a (normalized) string:
* def foo = { a: 1, b: 2 }
* string str1 = foo
* string str2 = { "a": 1, "b": 2 }
* assert str1 == str2
You can also get an ordered list of keys / values at any time:
* def vals = karate.valuesOf(foo)
* match vals == [1, 2]
* def keys = karate.keysOf(foo)
* match keys == ['a', 'b']
I have a DataFrame with a MultiIndex with 3 levels:
id foo bar col1
0 1 a -0.225873
2 a -0.275865
2 b -1.324766
3 1 a -0.607122
2 a -1.465992
2 b -1.582276
3 b -0.718533
7 1 a -1.904252
2 a 0.588496
2 b -1.057599
3 a 0.388754
3 b -0.940285
Preserving the id index level, I want to sum along the foo and bar levels, but with different values for each id.
For example, for id = 0 I want to sum over foo = [1] and bar = [["a", "b"]], for id = 3 I want to sum over foo = [2] and bar = [["a", "b"]], and for id = 7 I want to sum over foo = [[1,2]] and bar = [["a"]]. Giving the result:
id col1
0 -0.225873
3 -3.048268
7 -1.315756
I have been trying something along these lines:
df.loc(axis = 0)[[(0, 1, ["a","b"]), (3, 2, ["a","b"]), (7, [1,2], "a")].sum()
Not sure if this is even possible. Any elegant solution (possibly removing the MultiIndex?) would be much appreciated!
The list of tuples is not the problem. The fact that each tuple does not correspond to a single index is the problem (Since a list isn't a valid key). If you want to index a Dataframe like this, you need to expand the lists inside each tuple to their own entries.
Define your options like the following list of dictionaries, then transform using a list comprehension and index using all individual entries.
d = [
{
'id': 0,
'foo': [1],
'bar': ['a', 'b']
},
{
'id': 3,
'foo': [2],
'bar': ['a', 'b']
},
{
'id': 7,
'foo': [1, 2],
'bar': ['a']
},
]
all_idx = [
(el['id'], i, j)
for el in d
for i in el['foo']
for j in el['bar']
]
# [(0, 1, 'a'), (0, 1, 'b'), (3, 2, 'a'), (3, 2, 'b'), (7, 1, 'a'), (7, 2, 'a')]
df.loc[all_idx].groupby(level=0).sum()
col1
id
0 -0.225873
3 -3.048268
7 -1.315756
A more succinct solution using slicers:
sections = [(0, 1, slice(None)), (3, 2, slice(None)), (7, slice(1,2), "a")]
pd.concat(df.loc[s] for s in sections).groupby("id").sum()
col1
id
0 -0.225873
3 -3.048268
7 -1.315756
Two things to note:
This may be less memory-efficient than the accepted answer since pd.concat creates a new DataFrame.
The slice(None)'s are mandatory, otherwise the index columns of the df.loc[s]'s mismatch when calling pd.concat.