
Alguien había publicado una publicación en el blog el mes pasado, pero se eliminó (no sé por qué), pero dediqué mucho tiempo a verificar el resultado de ChatGPT, así que creo que es útil publicar mi experiencia (nuevamente).
Se solicitó a ChatGPT que convirtiera este algoritmo para agrupar anagramas en ABAP:
class Solution {
public List<List<String>> groupAnagrams(String[] strs) {
if (strs.length == 0) return new ArrayList();
Map<String, List> ans = new HashMap<String, List>();
int[] count = new int[26];
for (String s : strs) {
Arrays.fill(count, 0);
for (char c : s.toCharArray()) count[c - 'a']++;
StringBuilder sb = new StringBuilder("");
for (int i = 0; i < 26; i++) {
sb.append('#');
sb.append(count[i]);
}
String key = sb.toString();
if (!ans.containsKey(key)) ans.put(key, new ArrayList());
ans.get(key).add(s);
}
return new ArrayList(ans.values());
}
}
Este fue el código generado por ChatGPT:
CLASS solution DEFINITION.
PUBLIC SECTION.
METHODS: group_anagrams IMPORTING strs TYPE string_table
RETURNING VALUE(rv_anagrams) TYPE t_t_string_table.
ENDCLASS.
CLASS solution IMPLEMENTATION.
METHOD group_anagrams.
DATA: ans TYPE t_t_string_table,
ca TYPE string,
key TYPE string.
IF lines( strs ) = 0.
rv_anagrams = VALUE #( ).
RETURN.
ENDIF.
CREATE DATA ans TYPE HASHED TABLE OF t_string_table
WITH UNIQUE KEY string.
LOOP AT strs INTO ca.
SORT ca BY character.
key = ca.
IF NOT ans IS INITIAL.
INSERT VALUE #( ca ) INTO TABLE ans-values INDEX key.
ELSE.
INSERT VALUE #( ( ca ) ) INTO TABLE ans INDEX key.
ENDIF.
ENDLOOP.
rv_anagrams = ans-values.
ENDMETHOD.
ENDCLASS.
¿No es agradable?
Es impresionante, pero no compila y el algoritmo es simplemente incorrecto, muchas aproximaciones. Tal vez pronto tengamos IA conectada a la base de conocimiento de Java y ABAP, pero por ahora tenemos algo aparentemente bueno, pero necesita mucho trabajo. Dejame explicar.
Traté de completar el código para que funcione. Antes de eso, creé esta clase de prueba ABAP que corresponde al resultado esperado del algoritmo (del código Java anterior) y luego convertí el algoritmo del código Java línea por línea y me aseguré de que la prueba tuviera éxito:
CLASS solution DEFINITION.
PUBLIC SECTION.
TYPES: t_t_string_table TYPE STANDARD TABLE OF string_table WITH DEFAULT KEY.
METHODS: group_anagrams IMPORTING strs TYPE string_table
RETURNING VALUE(rv_anagrams) TYPE t_t_string_table.
ENDCLASS.
CLASS solution IMPLEMENTATION.
METHOD group_anagrams.
TYPES: ty_count TYPE STANDARD TABLE OF i WITH EMPTY KEY,
BEGIN OF ty_ans_line,
mapkey TYPE string,
mapvalue TYPE string_table,
END OF ty_ans_line,
ty_ans TYPE HASHED TABLE OF ty_ans_line WITH UNIQUE KEY mapkey.
IF lines( strs ) = 0. rv_anagrams = VALUE #( ). RETURN. ENDIF.
DATA(ans) = VALUE ty_ans( ).
DATA(count) = VALUE ty_count( FOR x = 0 WHILE x < 26 ( ) ).
LOOP AT strs INTO DATA(s).
DO lines( count ) TIMES. count[ sy-index ] = 0. ENDDO.
LOOP AT VALUE string_table( FOR off = 0 WHILE off < strlen( s ) ( substring( val = s off = off len = 1 ) ) ) INTO DATA(c).
DATA(index) = cl_abap_conv_out_ce=>uccpi( c ) - cl_abap_conv_out_ce=>uccpi( 'a' ) + 1.
count[ index ] = count[ index ] + 1.
ENDLOOP.
DATA(sb) = VALUE string_table( ).
DO 26 TIMES.
APPEND `#` TO sb.
APPEND |{ count[ sy-index ] }| TO sb.
ENDDO.
DATA(key) = concat_lines_of( table = sb ).
IF NOT line_exists( ans[ mapkey = key ] ). INSERT VALUE #( mapkey = key ) INTO TABLE ans. ENDIF.
ASSIGN ans[ mapkey = key ]-mapvalue TO FIELD-SYMBOL(<mapvalue>).
INSERT s INTO TABLE <mapvalue>.
ENDLOOP.
rv_anagrams = VALUE #( FOR <ans_line> IN ans ( <ans_line>-mapvalue ) ).
ENDMETHOD.
ENDCLASS.
CLASS ltc_main DEFINITION FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
METHODS test FOR TESTING.
ENDCLASS.
CLASS ltc_main IMPLEMENTATION.
METHOD test.
DATA(words) = VALUE string_table(
( `are` ) ( `bat` ) ( `ear` ) ( `code` ) ( `tab` ) ( `era` ) ).
DATA(answer) = NEW solution( )->group_anagrams( words ).
cl_abap_unit_assert=>assert_equals( act = answer exp = VALUE solution=>t_t_string_table(
( VALUE #( ( `are` ) ( `ear` ) ( `era` ) ) )
( VALUE #( ( `bat` ) ( `tab` ) ) )
( VALUE #( ( `code` ) ) ) ) ).
ENDMETHOD.
ENDCLASS.
Luego quería ver cómo corregir la versión de ChatGPT con la menor cantidad de cambios posibles. Ese es el resultado y debajo está la captura de pantalla de Diff:
CLASS solution DEFINITION.
PUBLIC SECTION.
TYPES: t_t_string_table TYPE STANDARD TABLE OF string_table WITH DEFAULT KEY.
METHODS: group_anagrams IMPORTING strs TYPE string_table
RETURNING VALUE(rv_anagrams) TYPE t_t_string_table.
ENDCLASS.
CLASS solution IMPLEMENTATION.
METHOD group_anagrams.
TYPES: BEGIN OF t_string_table,
string TYPE string,
mapvalue TYPE string_table,
END OF t_string_table,
t_string_table_2 TYPE HASHED TABLE OF t_string_table WITH UNIQUE KEY string.
DATA: ans TYPE REF TO t_string_table_2,
key TYPE string.
IF lines( strs ) = 0.
rv_anagrams = VALUE #( ).
RETURN.
ENDIF.
CREATE DATA ans TYPE HASHED TABLE OF t_string_table
WITH UNIQUE KEY string.
LOOP AT strs INTO DATA(s).
DATA(ca) = VALUE string_table( FOR off = 0 WHILE off < strlen( s ) ( substring( val = s off = off len = 1 ) ) ).
SORT ca BY table_line.
key = concat_lines_of( table = ca ).
IF NOT line_exists( ans->*[ string = key ] ).
INSERT VALUE #( string = key ) INTO TABLE ans->*.
ENDIF.
ASSIGN ans->*[ string = key ]-mapvalue TO FIELD-SYMBOL(<mapvalue>).
INSERT s INTO TABLE <mapvalue>.
ENDLOOP.
rv_anagrams = VALUE #( FOR <ans_line> IN ans->* ( <ans_line>-mapvalue ) ).
ENDMETHOD.
ENDCLASS.
Diferencia entre el código ChatGPT y el código corregido con cambios mínimos
Lo que me tomó hacer estas correcciones:
Conclusión: me tomó 3 veces más tiempo encontrar cómo arreglar el programa con cambios mínimos en lugar de escribir el algoritmo desde cero.
(3x es una estimación mía)
Pero supongo que ChatGPT podría entrenarse con un código ABAP equivalente al código Java y tal vez eso daría como resultado un código más reutilizable en el futuro…
Posiblemente, ChatGPT podría usarse solo para generar una lógica simple. Veamos si alguien puede proponer casos de uso reales, y no solo «oh, mira cómo se ve bien el código» sin verificar «lo que se necesita para arreglar el código».
Calle Eloy Gonzalo, 27
Madrid, Madrid.
Código Postal 28010
Paseo de la Reforma 26
Colonia Juárez, Cuauhtémoc
Ciudad de México 06600
Real Cariari
Autopista General Cañas,
San José, SJ 40104
Av. Jorge Basadre 349
San Isidro
Lima, LIM 15073