Algoritmo para el Cifrado Cesar en Go, común cuando inicias en criptografía y fácil de implementar, solo que en momentos de presión puedes llegar a hacer algo complicado cuando en realidad lo puedes resolver con un poco de aritmética (simple).
// Filtramos el slice sin crear copias extras
n := 0
for _, x := range slice {
if keep(x) { // Condición para mantener el elemento
slice[n] = x
n++
}
}
slice = slice[:n] // Ajustamos el tamaño finalAlgoritmo para el Cifrado Cesar en Go, común cuando inicias en criptografía y fácil de implementar, solo que en momentos de presión puedes llegar a hacer algo complicado cuando en realidad lo puedes resolver con un poco de aritmética (simple).
package main
import "fmt"
type task struct {
title string
descripcion string
ok bool
createAt int64
}
func main() {
// 1. Datos de prueba
tasks := []task{
{title: "Aprender Go", ok: true},
{title: "Ir al gym", ok: false},
{title: "Mejorar Inglés", ok: true},
{title: "Proyecto personal", ok: false},
}
fmt.Println("Antes:", len(tasks))
// 2. EL ALGORITMO DE FILTRADO
n := 0
for i := range tasks {
// "Si la tarea NO está lista (ok == false), la mantenemos"
if !tasks[i].ok {
tasks[n] = tasks[i]
n++
}
}
// 3. RE-SLICING: Ajustamos el tamaño al nuevo conteo
tasks = tasks[:n]
// 4. Resultado
fmt.Println("Después:", len(tasks))
for _, v := range tasks {
fmt.Printf("- %s (Estado: %v)\n", v.title, v.ok)
}
}
package main
import (
"reflect"
"testing"
)
func TestFilterTasksInPlace(t *testing.T) {
// Definimos los casos de prueba (Table-driven tests)
tests := []struct {
name string
input []task
expected []task
}{
{
name: "Filtrar algunas completadas",
input: []task{
{title: "T1", ok: true},
{title: "T2", ok: false},
{title: "T3", ok: true},
},
expected: []task{
{title: "T2", ok: false},
},
},
{
name: "Todas completadas (debe quedar vacío)",
input: []task{
{title: "T1", ok: true},
{title: "T2", ok: true},
},
expected: []task{},
},
{
name: "Ninguna completada (debe quedar igual)",
input: []task{
{title: "T1", ok: false},
{title: "T2", ok: false},
},
expected: []task{
{title: "T1", ok: false},
{title: "T2", ok: false},
},
},
{
name: "Slice vacío",
input: []task{},
expected: []task{},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Ejecutamos tu algoritmo
result := FilterTasksInPlace(tt.input)
// Comparamos el resultado con lo esperado
// reflect.DeepEqual es genial para comparar slices/structs
if !reflect.DeepEqual(result, tt.expected) {
t.Errorf("error en %s: esperado %v, obtenido %v", tt.name, tt.expected, result)
}
})
}
}
graph TD
%% --- ESTILOS ---
%% Definimos colores claros y bordes definidos para máxima claridad
classDef inicioEnd fill:#f9f,stroke:#333,stroke-width:2px,rx:15,ry:15,color:black;
classDef proceso fill:#e3f2fd,stroke:#1565c0,stroke-width:1px,color:black;
classDef decision fill:#fffde7,stroke:#fbc02d,stroke-width:1px,color:black;
classDef datos fill:#e8f5e9,stroke:#2e7d32,stroke-width:1px,color:black;
%% --- NODOS PRINCIPALES ---
Start((Inicio)):::inicioEnd
%% Fase 1: Inicialización
InitN[n := 0<br/>Indice de escritura]:::proceso
%% Fase 2: Bucle
ForLoop{"¿Hay más<br/>elementos x en<br/>slice?"}:::decision
%% Fase 3: Condición
IfKeep{"¿keep(x)?<br/>(Condición<br/>cumplida)"}:::decision
%% Fase 4: Acciones dentro del IF
AssignX["slice[n] = x<br/>(Se guarda x en<br/>posición válida)"]:::proceso
IncN[n++<br/>(Avanzar indice<br/>de escritura)]:::proceso
%% Fase 5: Finalización
Reslice["slice = slice[:n]<br/>(Ajuste final del tamaño)"]:::proceso
End((Fin)):::inicioEnd
%% --- CONEXIONES (FLUJO) ---
Start --> InitN
InitN --> ForLoop
%% Flujo dentro del bucle
ForLoop -- "Sí" --> IfKeep
%% Flujo si la condición keep(x) es verdadera
IfKeep -- "Sí (True)" --> AssignX
AssignX --> IncN
IncN --> ForLoop %% Vuelve al inicio del bucle
%% Flujo si la condición keep(x) es falsa
IfKeep -- "No (False)" --> ForLoop %% Salta la asignación y vuelve al bucle
%% Salida del bucle y finalización
ForLoop -- "No (Fin)" --> Reslice
Reslice --> End