Решение на Форматиране на импорти от Юлиян Палов

Обратно към всички решения

Към профила на Юлиян Палов

Резултати

  • 19 точки от тестове
  • 0 бонус точки
  • 19 точки общо
  • 19 успешни тест(а)
  • 1 неуспешни тест(а)

Код

use std::collections::HashMap;
pub struct Import<'a>(pub &'a [&'a str]);
#[derive(Clone, Copy)]
pub enum Order
{
Original,
Sorted,
}
pub fn format_flat(imports: &[Import], order: Order) -> Vec<String>
{
let imports_str: Vec<String> = imports
.iter()
.map(|import| import.0.join("::"))
.collect();
match order
{
Order::Original =>
{
let mut seen = std::collections::HashSet::new();
let mut unique = Vec::new();
for import in imports_str
{
if seen.insert(import.clone())
{
unique.push(import);
}
}
unique
}
Order::Sorted =>
{
let mut set = std::collections::HashSet::new();
let mut unique = Vec::new();
for import in imports_str
{
if set.insert(import.clone())
{
unique.push(import);
}
}
unique.sort();
unique
}
}
}
#[derive(Default, Clone)]
struct Node {
imported: bool,
children: Vec<(String, Node)>,
children_map: HashMap<String, usize>,
}
impl Node {
fn add_import(&mut self, path: &[&str], pos: usize)
{
if pos >= path.len()
{
self.imported = true;
}
else
{
let name = path[pos].to_string();
let idx = if let Some(&idx) = self.children_map.get(&name)
{
idx
}
else
{
self.children.push((name.clone(), Node::default()));
let idx = self.children.len() - 1;
self.children_map.insert(name.clone(), idx);
idx
};
self.children[idx].1.add_import(path, pos + 1);
}
}
}
fn format_node
(
name: &str,
node: &Node,
indent: usize,
order: &Order,
) -> String {
let indent_str = " ".repeat(indent * 4);
let next_indent_str = " ".repeat((indent + 1) * 4);
if node.children.is_empty() && node.imported
{
return format!("{}{}", indent_str, name);
}
let mut result = String::new();
result.push_str(&format!("{}{}::{{\n", indent_str, name));
let mut items = Vec::new();
if node.imported
{
items.push(("self".to_string(), None));
}
for (child_name, child_node) in &node.children
{
items.push((child_name.clone(), Some(child_node)));
}
let (self_item, mut items_to_sort) = if node.imported
{
(Some(items[0].clone()), items[1..].to_vec())
}
else
{
(None, items.clone())
};
match order
{
Order::Original => {}
Order::Sorted =>
{
items_to_sort.sort_by(|a, b| a.0.cmp(&b.0));
}
}
items = Vec::new();
if let Some(self_item) = self_item
{
items.push(self_item);
}
items.extend(items_to_sort);
for (item_name, child_node_option) in items
{
if let Some(child_node) = child_node_option {
let child_str = format_node(&item_name, child_node, indent + 1, order);
result.push_str(&child_str);
}
else
{
result.push_str(&format!("{}{}", next_indent_str, item_name));
}
result.push_str(",\n");
}
result.push_str(&format!("{}}}", indent_str));
if indent == 0 {
result.push('\n');
}
result
}
pub fn format_nested(imports: &[Import], order: Order) -> Vec<String>
{
let mut root = Node::default();
let mut seen_imports = std::collections::HashSet::new();
for import in imports
{
let path_vec = import.0.to_vec();
if seen_imports.insert(path_vec.clone())
{
root.add_import(&path_vec, 0);
}
}
let mut results = Vec::new();
let mut top_level_crates = root.children.clone();
match order
{
Order::Original => {}
Order::Sorted =>
{
top_level_crates.sort_by(|a, b| a.0.cmp(&b.0));
}
}
for (crate_name, crate_node) in top_level_crates
{
let formatted = format_node(&crate_name, &crate_node, 0, &order);
results.push(formatted);
}
results
}
#[test]
fn test_basic() {
let imports = &[
Import(&["my_crate", "a"]),
Import(&["my_crate", "b", "B1"]),
Import(&["my_crate", "b", "B2"]),
Import(&["my_crate", "c"]),
];
assert_eq!(
format_flat(imports, Order::Sorted),
&[
"my_crate::a",
"my_crate::b::B1",
"my_crate::b::B2",
"my_crate::c",
]
);
assert_eq!(
format_nested(imports, Order::Sorted),
&[
concat!(
"my_crate::{\n",
" a,\n",
" b::{\n",
" B1,\n",
" B2,\n",
" },\n",
" c,\n",
"}\n",
)
]
);
}

Лог от изпълнението

Compiling solution v0.1.0 (/tmp/d20241203-1739405-foq45/solution)
    Finished test [unoptimized + debuginfo] target(s) in 1.41s
     Running tests/solution_test.rs (target/debug/deps/solution_test-1428e1090729d165)

running 20 tests
test solution_test::test_flat_empty ... ok
test solution_test::test_flat_multi_crate ... ok
test solution_test::test_flat_original ... ok
test solution_test::test_flat_original_duplicates ... ok
test solution_test::test_flat_sorted ... ok
test solution_test::test_flat_sorted_duplicates ... ok
test solution_test::test_nested_basic ... ok
test solution_test::test_nested_deep ... ok
test solution_test::test_nested_empty ... ok
test solution_test::test_nested_only_crate ... FAILED
test solution_test::test_nested_original ... ok
test solution_test::test_nested_original_2 ... ok
test solution_test::test_nested_original_duplicates ... ok
test solution_test::test_nested_original_multi_crate ... ok
test solution_test::test_nested_original_self ... ok
test solution_test::test_nested_sorted ... ok
test solution_test::test_nested_sorted_2 ... ok
test solution_test::test_nested_sorted_duplicates ... ok
test solution_test::test_nested_sorted_multi_crate ... ok
test solution_test::test_nested_sorted_self ... ok

failures:

---- solution_test::test_nested_only_crate stdout ----
thread 'solution_test::test_nested_only_crate' panicked at 'assertion failed: `(left == right)`
  left: `["my_crate"]`,
 right: `["my_crate\n"]`', tests/solution_test.rs:132:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace


failures:
    solution_test::test_nested_only_crate

test result: FAILED. 19 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

error: test failed, to rerun pass `--test solution_test`

История (2 версии и 0 коментара)

Юлиян качи първо решение на 02.12.2024 00:26 (преди 10 месеца)

Юлиян качи решение на 02.12.2024 01:24 (преди 10 месеца)

-use std::collections::{BTreeMap, HashMap};
+use std::collections::HashMap;
-#[derive(Debug)]
pub struct Import<'a>(pub &'a [&'a str]);
-#[derive(Debug, PartialEq)]
+#[derive(Clone, Copy)]
pub enum Order
{
Original,
Sorted,
}
-#[derive(Debug, Default)]
-struct Node<'a>
+pub fn format_flat(imports: &[Import], order: Order) -> Vec<String>
{
- children: BTreeMap<&'a str, Node<'a>>,
- is_self: bool,
-}
+ let imports_str: Vec<String> = imports
+ .iter()
+ .map(|import| import.0.join("::"))
+ .collect();
-impl<'a> Node<'a>
-{
- fn new() -> Self
+ match order
{
- Self
+ Order::Original =>
{
- children: BTreeMap::new(),
- is_self: false,
+ let mut seen = std::collections::HashSet::new();
+ let mut unique = Vec::new();
+ for import in imports_str
+ {
+ if seen.insert(import.clone())
+ {
+ unique.push(import);
+ }
+ }
+ unique
}
+ Order::Sorted =>
+ {
+ let mut set = std::collections::HashSet::new();
+ let mut unique = Vec::new();
+ for import in imports_str
+ {
+ if set.insert(import.clone())
+ {
+ unique.push(import);
+ }
+ }
+ unique.sort();
+ unique
+ }
}
+}
- fn insert(&mut self, parts: &[&'a str])
+#[derive(Default, Clone)]
+struct Node {
+ imported: bool,
+ children: Vec<(String, Node)>,
+ children_map: HashMap<String, usize>,
+}
+
+impl Node {
+ fn add_import(&mut self, path: &[&str], pos: usize)
{
- if parts.is_empty()
+ if pos >= path.len()
{
- return;
- }
-
- let (first, rest) = parts.split_first().unwrap();
- let child = self.children.entry(first).or_insert_with(Node::new);
- if rest.is_empty()
- {
- child.is_self = true;
+ self.imported = true;
}
else
{
- child.insert(rest);
+ let name = path[pos].to_string();
+ let idx = if let Some(&idx) = self.children_map.get(&name)
+ {
+ idx
+ }
+ else
+ {
+ self.children.push((name.clone(), Node::default()));
+ let idx = self.children.len() - 1;
+ self.children_map.insert(name.clone(), idx);
+ idx
+ };
+ self.children[idx].1.add_import(path, pos + 1);
}
}
+}
- fn format_nested(&self, indent: usize) -> String
+fn format_node
+(
+ name: &str,
+ node: &Node,
+ indent: usize,
+ order: &Order,
+) -> String {
+ let indent_str = " ".repeat(indent * 4);
+ let next_indent_str = " ".repeat((indent + 1) * 4);
+
+ if node.children.is_empty() && node.imported
{
- let mut result = String::new();
- let indentation = " ".repeat(indent);
+ return format!("{}{}", indent_str, name);
+ }
- if self.is_self
+ let mut result = String::new();
+ result.push_str(&format!("{}{}::{{\n", indent_str, name));
+
+ let mut items = Vec::new();
+
+ if node.imported
+ {
+ items.push(("self".to_string(), None));
+ }
+
+ for (child_name, child_node) in &node.children
+ {
+ items.push((child_name.clone(), Some(child_node)));
+ }
+
+ let (self_item, mut items_to_sort) = if node.imported
+ {
+ (Some(items[0].clone()), items[1..].to_vec())
+ }
+ else
+ {
+ (None, items.clone())
+ };
+
+ match order
+ {
+ Order::Original => {}
+ Order::Sorted =>
{
- result.push_str(&format!("{}self,\n", indentation));
+ items_to_sort.sort_by(|a, b| a.0.cmp(&b.0));
}
+ }
- for (key, child) in &self.children
+ items = Vec::new();
+ if let Some(self_item) = self_item
+ {
+ items.push(self_item);
+ }
+ items.extend(items_to_sort);
+
+ for (item_name, child_node_option) in items
+ {
+ if let Some(child_node) = child_node_option {
+ let child_str = format_node(&item_name, child_node, indent + 1, order);
+ result.push_str(&child_str);
+ }
+ else
{
- if child.children.is_empty()
- {
- result.push_str(&format!("{}{},\n", indentation, key));
- }
- else
- {
- result.push_str(&format!("{}{}::{{\n", indentation, key));
- result.push_str(&child.format_nested(indent + 1));
- result.push_str(&format!("{}}},\n", indentation));
- }
+ result.push_str(&format!("{}{}", next_indent_str, item_name));
}
-
- result
+ result.push_str(",\n");
}
-}
-pub fn format_flat(imports: &[Import], order: Order) -> Vec<String>
-{
- let mut unique_imports: Vec<&Import> = imports.iter().collect();
- unique_imports.sort_unstable_by_key(|import| import.0);
- unique_imports.dedup_by_key(|import| import.0);
+ result.push_str(&format!("{}}}", indent_str));
- if order == Order::Sorted
- {
- unique_imports.sort_unstable_by(|a, b| a.0.cmp(&b.0));
+ if indent == 0 {
+ result.push('\n');
}
- unique_imports
- .into_iter()
- .map(|import| import.0.join("::"))
- .collect()
+ result
}
pub fn format_nested(imports: &[Import], order: Order) -> Vec<String>
{
- let mut trees: HashMap<&str, Node> = HashMap::new();
+ let mut root = Node::default();
+ let mut seen_imports = std::collections::HashSet::new();
- for import in imports
+ for import in imports
{
- if let Some((first, rest)) = import.0.split_first()
+ let path_vec = import.0.to_vec();
+ if seen_imports.insert(path_vec.clone())
{
- let tree = trees.entry(first).or_insert_with(Node::new);
- tree.insert(rest);
+ root.add_import(&path_vec, 0);
}
}
- let mut crates: Vec<_> = trees.into_iter().collect();
+ let mut results = Vec::new();
+ let mut top_level_crates = root.children.clone();
- if order == Order::Sorted
+ match order
{
- crates.sort_by_key(|(key, _)| *key);
+ Order::Original => {}
+ Order::Sorted =>
+ {
+ top_level_crates.sort_by(|a, b| a.0.cmp(&b.0));
+ }
}
- crates
- .into_iter()
- .map(|(krate, node)|
- {
- let mut result = String::new();
- result.push_str(&format!("{}::{{\n", krate));
- result.push_str(&node.format_nested(1));
- result.push_str("}\n");
- result
- })
- .collect()
+ for (crate_name, crate_node) in top_level_crates
+ {
+ let formatted = format_node(&crate_name, &crate_node, 0, &order);
+ results.push(formatted);
+ }
+
+ results
}
#[test]
fn test_basic() {
let imports = &[
Import(&["my_crate", "a"]),
Import(&["my_crate", "b", "B1"]),
Import(&["my_crate", "b", "B2"]),
Import(&["my_crate", "c"]),
];
assert_eq!(
format_flat(imports, Order::Sorted),
&[
"my_crate::a",
"my_crate::b::B1",
"my_crate::b::B2",
"my_crate::c",
]
);
assert_eq!(
format_nested(imports, Order::Sorted),
&[
concat!(
"my_crate::{\n",
" a,\n",
" b::{\n",
" B1,\n",
" B2,\n",
" },\n",
" c,\n",
"}\n",
)
]
);
}