I have an object
I try to get access to field "english"
val englishSentence = dbField::class.declaredMemberProperties.filter { it.name == "english" }[0]
But when I
model.addAttribute("sentence", englishSentence)
I get val com.cyrillihotin.grammartrainer.entity.Sentence.english: kotlin.String
while I expect bla
You can use the call function on a KProperty to get its value from the object.
val dbField = Sentence(1, "bla-eng", "bla-rus")
val value = dbField::class.declaredMemberProperties.find { it.name == "english" }!!.call(dbField)
println(value)
Output: bla-eng
Remember that data type of value is Any here. You need to cast it manually to the desired data type.
If you want to list all the properties with their values, you can do this:
dbField::class.declaredMemberProperties.forEach {
println("${it.name} -> ${it.call(dbField)}")
}
Output:
english -> bla-eng
id -> 1
russian -> bla-rus
Do you mean this?
data class Sentence(val id:Int, val english:String, val russian:String)
val dbField = Sentence(1, "blaEng", "blaRus")
val englishProp = dbField::class.declaredMemberProperties.first { it.name == "english" }as KProperty1<Sentence, String>
println(englishProp.get(dbField))
It prints blaEng
Related
I have API that post and get dates:
this is the data class:
data class PlannerGet(
val date: String,
val endTime: String,
val id: Int,
val location: String,
val note: String,
val startTime: String,
val title: String
)
and i am using this library for the calendar:
https://github.com/VarunBarad/Highlightable-Calendar-View
now in the fragment i was able to highlight certain days like this:
HighlightableCalendarView.dayDecorators = listOf(
DayDecorator(
Calendar.getInstance().apply {
set(Calendar.DAY_OF_MONTH, 4)
},
Color.parseColor("#ffffff"),
Color.parseColor("#ff0000")
),
)
but i want to highlight the days from API
i tried to make it like this:
HighlightableCalendarView.dayDecorators = listOf(
DayDecorator(
Calendar.getInstance().apply {
set(PlannerGet.date)
},
Color.parseColor("#ffffff"),
Color.parseColor("#ff0000")
),
)
but i am having a problem with "set" it show "None of the following functions can be called with the arguments supplied."
i tried to add "toInt()" and still the same problem.
what is the correct way to achieve this?
This is because the params which you are passing do not match the required params.
Calendar.getInstance().apply {
set(Calendar.DAY_OF_MONTH, 4)
}
The set functions accept the int field, int value but you are passing the params as the string
PlannerGet.date
The function set
public void set(int field, int value) {
throw new RuntimeException("Stub!");
}
If you want the date to be passed from the API dates please convert the string dates to java Date object.
SOLUTION:
if (response?.body().toString() == "[]") {
}
else if (response.isSuccessful) {
response.body()?.forEach {
getplanner.add(it)
Log.e("gggg gggg",getplanner.toString())
Log.e("gggg ddddd",getplanner[0].date)
}
val list = arrayListOf<DayDecorator>()
for (dsds in getplanner) {
list.add( DayDecorator(
Calendar.getInstance().apply {
// getplanner[0].date
val input_date = dsds.date
val format1 = SimpleDateFormat("yyyy-MM-dd")
var dt1: Date? = null
dt1 = format1.parse(input_date)
val format2: DateFormat = SimpleDateFormat("dd")
val strMonth: String = format2.format(dt1)
val month = strMonth.toInt()
Log.e("dateinplanner", "" + month)
set(Calendar.DAY_OF_MONTH, month)
},
Color.parseColor("#ffffff"),
Color.parseColor("#1AB7B8")
))
}
HighlightableCalendarView.dayDecorators = list
I have an ConfigEntry class defined as
case class ConfigEntry(
key: String,
value: String
)
and a list:
val list: List[ConfigEntry] = List(
ConfigEntry("general.first", "general first value"),
ConfigEntry("general.second", "general second value"),
ConfigEntry("custom.first", "custom first value"),
ConfigEntry("custom.second", "custom second value")
)
Given a list of ConfigEntry, I want a map from property -> map of entries that satisfy that property
As an example, if I have
def getConfig: Map[String, Map[String, String]] = {
def getKey(key: String, index: Int): String = key.split("\\.")(index)
list.map { config =>
getKey(config.key, 0) -> Map(getKey(config.key, 1) -> config.value)
}.toMap
}
I get result
res0: Map[String,Map[String,String]] =
Map(
"general" ->
Map("second" -> "general second value"),
"custom" ->
Map("second" -> "custom second value")
)
and it should be
res0: Map[String,Map[String,String]] =
Map(
"general" ->
Map(
"first" -> "general first value",
"second" -> "general second value"
),
"custom" ->
Map(
"first" -> "custom first value",
"second" -> "custom second value"
)
)
The first record from the list is missing. It's probably through .toMap
How can I do this?
Thank you for any help given
You can do something like this:
final case class ConfigEntry(
key: String,
value: String
)
type Config = Map[String, Map[String, String]]
def getConfig(data: List[ConfigEntry]): Config =
data
.view
.map(e => e.key.split('.').toList -> e.value)
.collect {
case (k1 :: k2 :: Nil, v) => k1 -> (k2 -> v)
}.groupMap(_._1)(_._2)
.view
.mapValues(_.toMap)
.toMap
Or something like this:
def getConfig(data: List[ConfigEntry]): Config = {
#annotation.tailrec
def loop(remaining: List[ConfigEntry], acc: Config): Config =
remaining match {
case ConfigEntry(key, value) :: xs =>
val newAcc = key.split('.').toList match {
case k1 :: k2 :: Nil =>
acc.updatedWith(k1) {
case Some(map) =>
val newMap = map.updatedWith(k2) {
case Some(v) =>
println(s"Overwriting previous value ${v} for the key: ${key}")
// Just overwrite the previous value.
Some(value)
case None =>
Some(value)
}
Some(newMap)
case None =>
Some(Map(k2 -> value))
}
case _ =>
println(s"Bad key: ${key}")
// Just skip this key.
acc
}
loop(remaining = xs, newAcc)
case Nil =>
acc
}
loop(remaining = data, acc = Map.empty)
}
I leave the handling of errors like duplicated keys or bad keys to the reader.
BTW, since this is a config, have you considered using a Config library?
Your map will only produce a 1 to 1 result. To do what you want you will need an accumulator (existing map) to do this.
Working with your existing code, if you're especially tied to how you're parsing your primary and secondary keys via getKey you can apply foldLeft to your list instead, with an empty map as an initial value.
list.foldLeft(Map.empty[String, Map[String, String]]) { (configs, configEntry) =>
val primaryKey = getKey(configEntry.key, 0)
val secondaryKey = getKey(configEntry.key, 1)
configs.get(primaryKey) match {
case None =>
configs.updated(primaryKey, Map(secondaryKey -> configEntry.value))
case Some(configMap) =>
configs.updated(primaryKey, configMap.updated(secondaryKey, configEntry.value))
}
}
Simply:
list.map { ce =>
val Array(l, r) = ce.key.split("\\.")
l -> (r -> ce.value)
} // List[(String, (String, String))]
.groupBy { case (k, _) => k } // Map[String, List[(String, (String, String))]]
.view.mapValues(_.map { case (_, v) => v }.toMap) // MapView[String, List[(String, String)]]
.toMap // Map[String, Map[String, String]]
As you can see in this screenshot while I'm in debug mode i can see a $loader variable that has the "() -> com.belandsoft.orariGTT.Model.RestRequestResponse, kotlin.Boolean>" content. It's possible to access these value at runtime in any way? The reflection can be helpfull in any way?
Sample code:
val mCollection: kotlin.collections.HashMap<Int, () -> Unit> = HashMap()
fun <T> myAddFunction(loader: () -> T) {
val elementCode = loader?.hashCode()
if (elementCode != null) {
mCollection[elementCode] = loader
}
}
fun myPrintFunction(): String {
val stringBuilder = StringBuilder()
var index = 0
for (i in mCollection.iterator()) {
stringBuilder.append("$index:[${i.value}] ")
index++
}
stringBuilder.toString()
}
This sadly produces a string like:
"053523:[()->kotlin.Unit], 453455:[()->kotlin.Unit]"
but I want to have:
"053523:[()->com.belandsoft.orariGTTView.MainFragment$startPtArrivalSearch$2$18839], 453455:[()->com.belandsoft.orariGTTView.MainFragment$startPtArrivalSearch$2$18845]"
Thanks.
I need to create a HashMap of directory-to-file in scala while I list all files in the directory. How can I achieve this in scala?
val directoryToFile = awsClient.listFiles(uploadPath).collect {
case path if !path.endsWith("/") => {
path match {
// do some regex matching to get directory & file names
case regex(dir, date) => {
// NEED TO CREATE A HASH MAP OF dir -> date. How???
}
case _ => None
}
}
}
The method listFiles(path: String) returns a Seq[String] of absolute path of all files in the path passed as argument to the function
Try to write more idiomatic Scala. Something like this:
val directoryToFile = (for {
path <- awsClient.listFiles(uploadPath)
if !path.endsWith("/")
regex(dir, date) <- regex.findFirstIn(path)
} yield dir -> date).sortBy(_._2).toMap
You can filter and then foldLeft:
val l = List("""/opt/file1.txt""", """/opt/file2.txt""")
val finalMap = l
.filter(!_.endsWith("/"))
.foldLeft(Map.empty[String, LocalDateTime])((map, s) =>
s match {
case regex(dir, date) => map + (dir -> date)
case _ => map
}
)
You can try something like this:
val regex = """(\d)-(\d)""".r
val paths = List("1-2", "3-4", "555")
for {
// Hint to Scala to produce specific type
_ <- Map("" -> "")
// Not sure why your !path.endsWith("/") is not part of regex
path#regex(a, b) <- paths
if path.startsWith("1")
} yield (a, b)
//> scala.collection.immutable.Map[String,String] = Map(1 -> 2)
Slightly more complicated if you need max:
val regex = """(\d)-(\d)""".r
val paths = List("1-2", "3-4", "555", "1-3")
for {
(_, ps) <-
( for {
path#regex(a, b) <- paths
if path.startsWith("1")
} yield (a, b)
).groupBy(_._1)
} yield ps.maxBy(_._2)
//> scala.collection.immutable.Map[String,String] = Map(1 -> 3)
I am very new to scala trying to understand by changing the equivalent java to scala so that I get better understanding.
How to convert java 8 map, filter and streams to scala ?
I have the following java 8 code which I am trying to convert to Scala :
public Set<String> getValidUsages(String itemId, long sNo, Date timeOfAccess) {
Set<String> itemSet = Sets.newHashSet();
TestWindows testWindows = items.get(itemId).getTestWindows();
final boolean isTV = existsEligibleTestWindow(testWindows.getTV(), timeOfAccess);
if (isTV) {
itemSet.add(TV);
} else {
final boolean isCableUseable = existsEligibleTestWindow(testWindows.getCableUse(), timeOfAccess);
final boolean isWifi = existsEligibleTestWindow(testWindows.getWifi(), timeOfAccess);
if (isCableUseable || isWifi) {
itemSet.add(MOVIE);
}
}
if (testWindows.getUsageIds() != null) {
itemSet.addAll(testWindows.getUsageIds()
.entrySet()
.stream()
.filter(entry -> existsEligibleTestWindow(entry.getValue(), timeOfAccess))
.map(Map.Entry::getKey)
.collect(Collectors.toSet()));
}
return itemSet;
}
private boolean existsEligibleTestWindow(List<TestWindow> windows, Date timeOfAccess) {
if (windows != null) {
return windows.stream()
.filter(w -> withinDateRange(timeOfAccess, w))
.findAny()
.isPresent();
}
return false;
}
private boolean withinDateRange(Date toCheck, TestWindow window) {
return toCheck.after(window.getStartTime()) && toCheck.before(window.getEndTime());
}
I tried :
def withinDateRange(toCheck: Date, window: TestWindow): Boolean = {
toCheck.after( window.getStartTime ) && toCheck.before( window.getEndTime )
}
def getValidUsages(itemId: String, sNo: Long, timeOfAccess: Date): Set[String] = {
var itemSet = Sets.newHashSet()
val testWindows = items.value(itemId).getTestWindows
val isTV = existsEligibleTestWindow(testWindows.get(0).getTV, timeOfAccess)
if (isTV) {
itemSet += TV
} else {
val isCableUseable = existsEligibleTestWindow(testWindows.get(0).getCableUse, timeOfAccess)
val isWifi = existsEligibleTestWindow(testWindows.get(0).getWifi, timeOfAccess)
if (isCableUseable || isWifi) {
itemSet += MOVIE
}
}
if (testWindows.get(0).getUsageIds != null) {
itemSet.addAll(testWindows.get(0).getUsageIds.entrySet().stream()
.filter((x) => existsEligibleTestWindow(x._2, timeOfAccess)).map(x => Map.Entry._1 )
.collect(Collectors.toSet()))
}
itemSet
}
def existsEligibleConsumptionWindow(windows: List[ConsumptionWindow], timeOfAccess: Date): Boolean = {
if (windows != null) {
return windows.exists((x) => withinDateRange(timeOfAccess, x))
}
false
}
But getting error while doing filter and stream. Can some one point to direct direction ? Any references ? I am getting error on getValidUsages :
compile error “cannot resolve reference project with such signature
This is somewhat difficult to answer since I am unfamiliar with some of the types you use. But if I guess there are types like the following:
trait Window {
def getStartTime: LocalDate
def getEndTime: LocalDate
}
trait TestWindows extends Window {
def getTV: List[Window]
def getCableUse: List[Window]
def getWifi: List[Window]
def getUsageIds: Map[String, List[Window]]
}
then you could just do this:
def withinDateRange(toCheck: LocalDate)(window: Window): Boolean =
window.getStartTime.isBefore(toCheck) && window.getEndTime.isAfter(toCheck)
// Nothing should ever be null in Scala. If it's possible you don't have any ConsumptionWindows you should either
// model it as an empty list or an Option[List[ConsumptionWindow]]
def existsEligibleTestWindow(windows: List[Window],
timeOfAccess: LocalDate): Boolean =
windows.exists(withinDateRange(timeOfAccess))
def getValidUsages(testWindows: TestWindows, timeOfAccess: LocalDate): Set[String] = {
val isTV = existsEligibleTestWindow(testWindows.getTV, timeOfAccess)
val isCableUse = existsEligibleTestWindow(testWindows.getCableUse, timeOfAccess)
val isWifi = existsEligibleTestWindow(testWindows.getWifi, timeOfAccess)
val tvOrMovie: Option[String] = if (isTV) Some("TV")
else if (isCableUse || isWifi) Some("MOVIE")
else None
val byUsageId = testWindows.getUsageIds.collect { case (key, windows) if existsEligibleTestWindow(windows, timeOfAccess) => key }.toSet
tvOrMovie.toSet ++ byUsageId
}
In your original code there was presumably some items value, but in the above I just assume you do TestWindows testWindows = items.get(itemId).getTestWindows() outside the getValidUsages function.
My example doesn't use java structures at all and just uses the scala core collections. The other main difference is that I use immutable data structures which is, I think, a little easier to follow and generally safer.
Some items of note:
1) The Option.toSet operation result in an empty set when called upon a None.
2) There is an example of function currying used for the withinDateRange method.
3) I obviously have no idea what your original types do and had to guess at the relevant parts.
The problem seems to be that you are using Java types in Scala while depending on scala's map & filter operations. This has its own troubles but if you convert the list/collections to a Scala's collections first (warning, Scala types are immutable by default), then you should be able to just use the map/filter operations without having to call java's stream() method.
def getValidUsages(itemId: String, sNo: long, timeOfAcess: Date): Set[String] = {
var itemSet: Set[String] = Sets.newHashSet()
val testWindows: TestWindows = items.get(itemId).getTestWindows()
val isTV: Boolean = existsEligibleTestWindow(testWindows.getTV(), timeOfAccess)
isTV match {
case true => itemSet.add(TV)
case false => {
val isCableUseable: Boolean = existsEligibleTestWindow(testWindows.getCableUse(), timeOfAcess)
val isWifi: Boolean = existsEligibleTestWindow(testWindows.getWifi(), timeOfAccess)
if(isCableUseable || isWifi) {
itemSet.add(MOVIE)
}
}
}
if(testWindows.getUsageIds() != null) {
itemSet.addAll(testWindows.getUsageIds()
.stream.
.filter(entry => existsEligibleTestWindow(entry._2, timeOfAccess))
.map(filteredData => Map.Entry._1)
.collect Collectors.toSet())
}
itemSet
}
def existsEligibleTestWindow(windows: List[TestWindow], timeOfAcess: Date): Boolean = {
windows match {
case null => false
case _ => windows.stream.filter(data => withinDateRange(timeOfAcess), data).findAny().isPresent
}
}
Good luck :)