
Узнает, узнает. #prog #math
Size: a a a
func getIDsForTextSearch(sortedIDs []string, spottedIDsWithDocCount map[string]int, paging paging) ([]string, int) {
var countDocsNeedForRequest int
var countIDsNeedToShow int
sortedByDateSpottedIDs := []string{}
IDsForSearch := []string{}
for _, k := range sortedIDs {
if _, wasSpotted := spottedIDsWithDocCount[k]; wasSpotted {
sortedByDateSpottedIDs = append(sortedByDateSpottedIDs, k)
}
}
if len(sortedByDateSpottedIDs) < paging.Offset + paging.Limit {
countIDsNeedToShow = len(sortedByDateSpottedIDs)
} else {
countIDsNeedToShow = paging.Offset + paging.Limit
}
for i := paging.Offset; i < countIDsNeedToShow; i++ {
id := sortedByDateSpottedIDs[i]
IDsForSearch = append(IDsForSearch, id)
countDocsNeedForRequest += spottedIDsWithDocCount[id]
}
return IDsForSearch, countDocsNeedForRequest
}
Конечно, имена по энтерпрайзной моде усложняют понимание этого кода, но я смог уловить его суть — другое дело, что для этого мне потребовалось переписать его на Rust (место для вашего саркастического комментария о моих умственных способностях). Как оказалось, смысл этого кода таков: взять из sortedIDs
строки, содержащиеся в spottedIDsWithDocCount
, и выделить из этой последовательности окно длиной paging.Limit
, начиная с paging.Offset
-го элемента, попутно просуммировав связанные с этими id количества. Код достаточно прямолинейный и неисправимо последовательный, так что киллер-фича Go — горутины — здесь не пригодится. Не буду утомлять вас промежуточными версиями переписывания и покажу сразу конечный результат:fn get_ids_for_text_search(
sorted_ids: &[String],
spotted_ids_with_doc_count: &HashMap<String, usize>,
paging: Paging,
) -> (Vec<String>, usize) {
sorted_ids
.iter()
.filter_map(|s| {
let &count = spotted_ids_with_doc_count.get(s)?;
Some((s, count))
})
.skip(paging.offset)
.take(paging.limit)
.fold((Vec::with_capacity(paging.limit), 0), |(mut ids, total), (s, count)| {
ids.push(s.clone());
(ids, total + count)
})
}
Vec<String>
и &[String]
fold
, понимание которого у многих новичков почему-то вызывает проблему)Option
?
sorted_ids
, выделить из них те, которые лежат в spotted_ids_with_doc_count
, пропустить первые paging.offset
из них, взять первые paging.limit
из них (выделив, таким образом, интересующий нас диапазон) и затем неразборчивое бормотание, получив список всех строк и сумму всех связанных с ними значений. Здесь практически нет явных изменений переменных, процесс описан скорее в терминах трансформации потока данных.sortedIDs
— в ржавом варианте обход заканчивается, когда набирается достаточно подходящих строк.sortedByDateSpottedIDs
будет как минимум countIDsNeedToShow
строк — в варианте ниже итоговый вектор просто будет содержать меньше paging.limit
строк, если их не хватает (это, кстати, можно считать как плюсом, так и минусом, но надо отметить, что нарушение этого ожидания в оригинальном варианте вызовет панику из-за некорректного индекса, а в моём варианте можно постфактум проверить длину возвращённого вектора).func getIDsForTextSearch(Всё при нём: единственный цикл, один слайс с предварительно выделенной памятью, ранний выход из цикла при достижении нужного количества строк... Что же не так? А вот что: наглядность отсутствует напрочь. Помимо двух возвращаемых значений, есть две технические переменные, которые нужно менять, и три условных оператора, которые нужно расставить в правильном порядке — или получить странные баги. Также тут есть пара мест для того, чтобы сделать ошибку на единицу. Но технически это всё ещё достаточно простой код. Вот только с запашком. Я бы на код-ревью подумал бы, стоит ли такой код пускать в прод.
sortedIDs []string,
spottedIDsWithDocCount map[string]int,
paging paging,
) ([]string, int) {
idsForSearch := make([]string, 0, paging.Limit)
skip := paging.Offset
iterated := 0
total := 0
for _, id := range sortedCallIDs {
if iterated >= paging.Limit {
break
}
count, spotted := spottedIDsWithDocCount[id]
if !spotted {
continue
}
if skip > 0 {
skip--
continue
}
iterated++
idsForSearch = append(idsForSearch, id)
total += count
}
return idsForSearch, total
}
func getIDsForTextSearch(sortedIDs []string, spottedIDsWithDocCount map[string]int, paging paging) ([]string, int) {
var countDocsNeedForRequest int
var countIDsNeedToShow int
sortedByDateSpottedIDs := []string{}
IDsForSearch := []string{}
for _, k := range sortedIDs {
if _, wasSpotted := spottedIDsWithDocCount[k]; wasSpotted {
sortedByDateSpottedIDs = append(sortedByDateSpottedIDs, k)
}
}
if len(sortedByDateSpottedIDs) < paging.Offset + paging.Limit {
countIDsNeedToShow = len(sortedByDateSpottedIDs)
} else {
countIDsNeedToShow = paging.Offset + paging.Limit
}
for i := paging.Offset; i < countIDsNeedToShow; i++ {
id := sortedByDateSpottedIDs[i]
IDsForSearch = append(IDsForSearch, id)
countDocsNeedForRequest += spottedIDsWithDocCount[id]
}
return IDsForSearch, countDocsNeedForRequest
}
Конечно, имена по энтерпрайзной моде усложняют понимание этого кода, но я смог уловить его суть — другое дело, что для этого мне потребовалось переписать его на Rust (место для вашего саркастического комментария о моих умственных способностях). Как оказалось, смысл этого кода таков: взять из sortedIDs
строки, содержащиеся в spottedIDsWithDocCount
, и выделить из этой последовательности окно длиной paging.Limit
, начиная с paging.Offset
-го элемента, попутно просуммировав связанные с этими id количества. Код достаточно прямолинейный и неисправимо последовательный, так что киллер-фича Go — горутины — здесь не пригодится. Не буду утомлять вас промежуточными версиями переписывания и покажу сразу конечный результат:fn get_ids_for_text_search(
sorted_ids: &[String],
spotted_ids_with_doc_count: &HashMap<String, usize>,
paging: Paging,
) -> (Vec<String>, usize) {
sorted_ids
.iter()
.filter_map(|s| {
let &count = spotted_ids_with_doc_count.get(s)?;
Some((s, count))
})
.skip(paging.offset)
.take(paging.limit)
.fold((Vec::with_capacity(paging.limit), 0), |(mut ids, total), (s, count)| {
ids.push(s.clone());
(ids, total + count)
})
}
Vec<String>
и &[String]
fold
, понимание которого у многих новичков почему-то вызывает проблему)Option
?
sorted_ids
, выделить из них те, которые лежат в spotted_ids_with_doc_count
, пропустить первые paging.offset
из них, взять первые paging.limit
из них (выделив, таким образом, интересующий нас диапазон) и затем неразборчивое бормотание, получив список всех строк и сумму всех связанных с ними значений. Здесь практически нет явных изменений переменных, процесс описан скорее в терминах трансформации потока данных.