
Узнает, узнает. #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 из них (выделив, таким образом, интересующий нас диапазон) и затем неразборчивое бормотание, получив список всех строк и сумму всех связанных с ними значений. Здесь практически нет явных изменений переменных, процесс описан скорее в терминах трансформации потока данных.


