如何在过去6个月的物体中找到特定的单词,并每周对其进行分类

  • 本文关键字:每周 单词 分类 6个 过去 kotlin
  • 更新时间 :
  • 英文 :


我是Kotlin的新手,正在努力找出如何做到最好。我调用了一个api调用,并将响应转换为对象列表:

data class JobAd(
val published: LocalDate?,
val title: String?,
val jobtitle: String?,
val description: String?
)

在api调用中,我搜索从今天到6个月前的所有招聘广告。例如,我得到了来自LocalDate.now()和6个月前LocalDate).now().minusMonths(6)的所有对象。我想遍历所有对象,看看对象中是否包含2个随机单词(java和kotlin(。我想检查标题、职务或描述中是否包含单词java或kotlin。我只需要在这些属性中点击一次单词java或kotlin,如果标题包含java或kodlin,请将其添加到列表中并检查下一个对象。如果不是title包含单词,也不是jobtitle,而是description包含单词,请将其添加到列表中并选中下一个对象。并根据当前周数将其添加到列表中。我希望输出是这样的:

(2022) Week 12 -> Java: 0, Kotlin: 1
(2022) Week 11 -> Java: 0, Kotlin: 0 (If some weeks does not have hit, i want to show to too)
...
(2021) Week 52 -> Java: 1, Kotlin: 2

这是我迄今为止的代码:

private fun findAdsBasedOnKeyWords(jobAds: MutableList<JobAd>, keywords: List<String>, from: LocalDate, to: LocalDate): MutableMap<Any, MutableMap<String, Any>> {
val resultMap = mutableMapOf<Any, MutableMap<String, Any>>()
val counter = mutableMapOf<String, Any>() //Meta data
for (jobAd: JobAd in jobAds) {
for (keyword: String in keywords) {
val weekNumber = DateParser.getWeekNumber(jobAd.published!!)
// Initialize placeholder data, to fill even empty weeks
resultMap.putIfAbsent(weekNumber, emptyMapOfKeywords(keywords, jobAd.published))
// Validate keyword exist in job ad
val contains = jobAd.toString().lowercase()
.contains(keyword.lowercase()) //Can be an issue if the toString gets overridden
if (contains) {
counter.putIfAbsent(keyword, 0)
counter.compute(keyword) { _, v -> v.toString().toInt() + 1 }
resultMap[weekNumber]!!.compute(keyword) { _, v -> v.toString().toInt() + 1 }
}
}
}
resultMap["total"] = counter
resultMap["period"] = mutableMapOf("from" to from, "to" to to)
logger.info("[{}] matches found", counter)
return resultMap
}
//Helper method to generate placeholder data
private fun emptyMapOfKeywords(keywords: List<String>, published: LocalDate): MutableMap<String, Any> {
val keywordMap = mutableMapOf<String, Any>()
for (keyword in keywords) {
keywordMap.putIfAbsent(keyword, 0)
}
keywordMap.putIfAbsent("from", DateParser.startOfWeekDate(published))//Monday of the week
keywordMap.putIfAbsent("to", DateParser.endOfWeekDate(published))//Sunday of the week
return keywordMap
}

有什么方法可以做得更好或优化它吗?请添加评论说明原因。

使用Maps来保存需要检查的各种类型的数据是一种非常极端的反模式。这是试图迫使强类型语言表现得像弱类型语言,从而失去使用类型所获得的所有保护。

当键在编译时是不知道的,并且您知道在运行时需要按键查找项时,映射是合适的。

因此,您应该创建用于保存结果的类,而不是MutableMap<Any, MutableMap<String, Any>>返回值。据我所知,您希望在输入范围内每周返回一系列行项目,这样您就可以创建一个这样的类来表示行项目,然后从函数中返回它们的简单列表。你目前也在返回范围,但我不知道你在用它做什么,所以我把它排除在外。

一年中的一周你要花很多时间,所以我认为用一个类来表示它,以及一些函数来帮助从LocalDate转换也会很有帮助。

data class LocalWeek(val year: Int, val week: Int)
fun LocalDate.toLocalWeek() = LocalWeek(year, get(IsoFields.WEEK_OF_WEEK_BASED_YEAR))
/** Gets every week represented in a range of dates. */
fun ClosedRange<LocalDate>.toLocalWeeks() = sequence {
var date = start
val lastExclusive = endInclusive + Period.ofWeeks(1)
while (date < lastExclusive ) {
yield(date.toLocalWeek())
date += Period.ofWeeks(1)
}
}
data class JobAdsSearchLineItem(
val localWeek: LocalWeek,
val keywordHitCountsByKeyword: Map<String, Int>
) {
fun toReadableString() =
"(${localWeek.year}) Week ${localWeek.week} -> " +
keywordHitCountsByKeyword.entries
.joinToString { (word, count) -> "$word: $count" }
}

使用toString()是脆弱的,就像您在代码注释中提到的那样。我会创建一个像这样的辅助函数来评估是否找到了一个术语:

fun JobAd.containsIgnoreCase(str: String): Boolean {
val value = str.lowercase()
return title.orEmpty().lowercase().contains(value)
|| jobtitle.orEmpty().lowercase().contains(value)
|| description.orEmpty().lowercase().contains(value)
}

由于您在发布日期使用!!,我假设这些值不需要为null。如果您使属性不可为null,那么处理起来会容易得多:

data class JobAd(
val published: LocalDate,
val title: String?,
val jobtitle: String?,
val description: String?
)

然后你的搜索功能可以这样写:

private fun findAdsBasedOnKeyWords(
jobAds: List<JobAd>,
keywords: List<String>,
from: LocalDate,
to: LocalDate
): List<JobAdsSearchLineItem> {
// Initialize empty results holders representing every week in the range
// Use an outer map here because we need to keep retrieving the inner maps by
// the week when iterating the input below.
val results = mutableMapOf<LocalWeek, MutableMap<String, Int>>()
for (localWeek in (from..to).toLocalWeeks()) {
results[localWeek] = mutableMapOf<String, Int>().apply {
for (keyword in keywords) {
put(keyword, 0)
}
}
}
for (jobAd in jobAds) {
val weekResults = results[jobAd.published.toLocalWeek()] ?: continue
for (keyword in keywords) {
if (jobAd.containsIgnoreCase(keyword)) {
weekResults[keyword] = weekResults.getValue(keyword) + 1
}
}
}
return results.entries.map { JobAdsSearchLineItem(it.key, it.value) }
}

要使用它,您可以调用此函数并使用toReadableString()函数来帮助从结果列表中生成输出。

最新更新