use rayon::prelude::*;
use std::{fs::File, io::{self, BufRead, BufReader}};
use std::path::Path;
use csv::ReaderBuilder;
use crate::models::{Review, GameSummary, LanguageSummary, FinalSummary,
ReviewSummary, LanguageTopReviews};
use std::time::Instant;
use std::collections::HashMap;
// Función principal para procesar los archivos CSV
pub fn process_csv_files(file_path: &str, num_threads: usize) -> io::Result<FinalSummary>
{
// Configurar el pool de threads de rayon
rayon::ThreadPoolBuilder::new()
.num_threads(num_threads)
.build_global()
.unwrap();
let path = Path::new(file_path);
let file = File::open(path)?;
let reader = BufReader::new(file);
// Usamos csv::ReaderBuilder si es CSV bien estructurado
let mut rdr = csv::Reader::from_reader(reader);
let mut reviews = Vec::new();
for result in [Link]() {
let review: Review = match result {
Ok(r) => r,
Err(_) => continue,
};
[Link](review);
}
let top_games = calculate_top_games(&reviews);
let top_languages = calculate_top_languages(&reviews);
Ok(FinalSummary {
padron: 123456, // Reemplazá con tu padrón real
top_games,
top_languages,
})
}
fn calculate_top_games(reviews: &[Review]) -> Vec<GameSummary> {
// Agrupar las reseñas por `app_name`
let game_reviews: HashMap<String, Vec<Review>> = reviews.par_iter()
.fold(HashMap::new, |mut acc, review| {
[Link](review.app_name.clone())
.or_insert_with(Vec::new)
.push([Link]());
acc
})
.reduce(HashMap::new, |mut acc, part| {
for (key, value) in part {
[Link](key)
.or_insert_with(Vec::new)
.extend(value);
}
acc
});
// Crear un vector con el número de reseñas por juego
let mut game_summary: Vec<(String, usize)> = game_reviews.iter()
.map(|(game, reviews)| ([Link](), [Link]()))
.collect();
// Ordenar por la cantidad de reseñas (de mayor a menor)
game_summary.sort_by(|a, b| [Link](&a.1));
// Seleccionar los top 10 juegos
game_summary.into_iter()
.take(3)
.map(|(game, count)| {
let languages = calculate_languages(&game_reviews[&game]); // Recalcular los idiomas
para cada juego
GameSummary {
game,
review_count: count as u32,
languages,
}
})
.collect()
}
fn calculate_languages(reviews: &[Review]) -> Vec<LanguageSummary> {
// Agrupar las reseñas por idioma
let mut language_reviews: HashMap<String, Vec<Review>> = reviews.par_iter()
.fold(HashMap::new, |mut acc, review| {
[Link]([Link]())
.or_insert_with(Vec::new)
.push([Link]());
acc
})
.reduce(HashMap::new, |mut acc, part| {
for (key, value) in part {
[Link](key)
.or_insert_with(Vec::new)
.extend(value);
}
acc
});
// Ordenar los idiomas por cantidad de reseñas (de mayor a menor)
let mut language_summary: Vec<(String, usize)> = language_reviews.iter()
.map(|(language, reviews)| ([Link](), [Link]()))
.collect();
language_summary.sort_by(|a, b| [Link](&a.1).then([Link](&b.0))); // Ordenar por
cantidad y alfabéticamente en caso de empate
// Seleccionar los 3 idiomas más utilizados
let top_languages = language_summary.into_iter()
.take(3)
.map(|(language, count)| {
let top_review = language_reviews[&language].iter()
.max_by_key(|r| r.votes_helpful)
.map(|review| ReviewSummary {
review: [Link](),
votes: review.votes_helpful,
})
.unwrap_or(ReviewSummary {
review: String::new(),
votes: 0,
});
LanguageSummary {
language,
review_count: count as u32,
top_review: top_review.review,
top_review_votes: top_review.votes,
}
})
.collect(); // Se agregó el `collect` correctamente aquí para que la función devuelva el
valor esperado
top_languages
}
fn calculate_top_languages(reviews: &[Review]) -> Vec<LanguageTopReviews> {
use rayon::prelude::*;
use std::collections::HashMap;
// Agrupar reseñas por idioma
let mut language_map: HashMap<String, Vec<Review>> = HashMap::new();
for review in [Link]().cloned() {
language_map
.entry([Link]())
.or_insert_with(Vec::new)
.push(review);
}
// Calcular el top 3 de idiomas más utilizados (orden alfabético en caso de empate)
let mut language_counts: Vec<(String, usize)> = language_map
.iter()
.map(|(lang, reviews)| ([Link](), [Link]()))
.collect();
language_counts.sort_by(|a, b| [Link](&a.1).then([Link](&b.0)));
language_counts
.into_iter()
.take(3)
.map(|(language, count)| {
let mut reviews = language_map.remove(&language).unwrap_or_default();
// Obtener el top 10 de reseñas más votadas
reviews.sort_by(|a, b| b.votes_helpful.cmp(&a.votes_helpful));
let top_reviews: Vec<ReviewSummary> = reviews
.into_iter()
.take(10)
.map(|r| ReviewSummary {
review: [Link],
votes: r.votes_helpful,
})
.collect();
LanguageTopReviews {
language,
review_count: count as u32,
top_reviews,
}
})
.collect()
}