Rumah >pembangunan bahagian belakang >Golang >Tukar nilai yang dipisahkan titik kepada struct Go menggunakan Python

Tukar nilai yang dipisahkan titik kepada struct Go menggunakan Python

王林
王林ke hadapan
2024-02-10 13:33:08997semak imbas

使用 Python 将点分隔值转换为 Go 结构

Dalam artikel ini, editor PHP Youzi akan memperkenalkan cara menggunakan Python untuk menukar nilai yang dipisahkan titik (seperti "key1.subkey1.subkey2") ke dalam struktur dalam bahasa Go. Proses transformasi ini berguna untuk mengekstrak dan memproses data daripada fail konfigurasi atau respons API. Kami akan menggunakan fungsi rekursif Python dan struktur bahasa Go untuk melaksanakan penukaran ini, dan memberikan contoh dan penjelasan kod terperinci. Selepas mengkaji artikel ini, pembaca akan dapat memproses dan menukar nilai yang dipisahkan titik dengan mudah, meningkatkan kecekapan dan fleksibiliti pemprosesan data.

Kandungan soalan

Ini adalah keperluan khusus untuk aplikasi yang boleh menukar konfigurasi (khususnya pelayan identiti wso2, kerana saya menggunakan pergi untuk menulis pengendali kubernetes untuknya). Tetapi ia benar-benar tidak relevan di sini. Saya ingin mencipta penyelesaian yang membolehkan pengurusan mudah bagi sejumlah besar peta konfigurasi untuk menjana struktur go. Konfigurasi ini dipetakan dalam .csv

Pautan ke .csv - my_configs.csv

Saya mahu, Tulis skrip python yang menjana struktur go secara automatik supaya sebarang perubahan pada konfigurasi aplikasi boleh dikemas kini dengan hanya melaksanakan skrip python untuk mencipta struktur go yang sepadan. Saya merujuk kepada konfigurasi aplikasi itu sendiri. Sebagai contoh, nama kunci toml dalam csv boleh ditukar/nilai baharu boleh ditambah.

Setakat ini saya telah berjaya mencipta skrip python yang hampir mencapai matlamat saya. Skripnya ialah,

import pandas as pd

def convert_to_dict(data):
    result = {}
    for row in data:
        current_dict = result
        for item in row[:-1]:
            if item is not none:
                if item not in current_dict:
                    current_dict[item] = {}
                current_dict = current_dict[item]
    return result

def extract_json_key(yaml_key):
    if isinstance(yaml_key, str) and '.' in yaml_key:
        return yaml_key.split('.')[-1]
    else:
        return yaml_key

def add_fields_to_struct(struct_string,go_var,go_type,json_key,toml_key):
    struct_string += str(go_var) + " " + str(go_type) + ' `json:"' + str(json_key) + ',omitempty" toml:"' +str(toml_key) + '"` ' + "\n"
    return struct_string

def generate_go_struct(struct_name, struct_data):
    struct_name="configurations" if struct_name == "" else struct_name
    struct_string = "type " + struct_name + " struct {\n"
    yaml_key=df['yaml_key'].str.split('.').str[-1]
    
    # base case: generate fields for the current struct level    
    for key, value in struct_data.items():
        selected_rows = df[yaml_key == key]

        if len(selected_rows) > 1:
            go_var = selected_rows['go_var'].values[1]
            toml_key = selected_rows['toml_key'].values[1]
            go_type=selected_rows['go_type'].values[1]
            json_key=selected_rows['json_key'].values[1]
        else:
            go_var = selected_rows['go_var'].values[0]
            toml_key = selected_rows['toml_key'].values[0]
            go_type=selected_rows['go_type'].values[0]
            json_key=selected_rows['json_key'].values[0]

        # add fields to the body of the struct
        struct_string=add_fields_to_struct(struct_string,go_var,go_type,json_key,toml_key)   

    struct_string += "}\n\n"
    
    # recursive case: generate struct definitions for nested structs
    for key, value in struct_data.items():
        selected_rows = df[yaml_key == key]

        if len(selected_rows) > 1:
            go_var = selected_rows['go_var'].values[1]
        else:
            go_var = selected_rows['go_var'].values[0]

        if isinstance(value, dict) and any(isinstance(v, dict) for v in value.values()):
            nested_struct_name = go_var
            nested_struct_data = value
            struct_string += generate_go_struct(nested_struct_name, nested_struct_data)
    
    return struct_string

# read excel
csv_file = "~/downloads/my_configs.csv"
df = pd.read_csv(csv_file)

# remove rows where all columns are nan
df = df.dropna(how='all')
# create the 'json_key' column using the custom function
df['json_key'] = df['yaml_key'].apply(extract_json_key)

data=df['yaml_key'].values.tolist() # read the 'yaml_key' column
data = pd.dataframe({'column':data}) # convert to dataframe

data=data['column'].str.split('.', expand=true) # split by '.'

nested_list = data.values.tolist() # convert to nested list
data=nested_list 

result_json = convert_to_dict(data) # convert to dict (json)

# the generated co code
go_struct = generate_go_struct("", result_json)

# write to file
file_path = "output.go"
with open(file_path, "w") as file:
    file.write(go_struct)

Masalahnya ialah (lihat bahagian bawah csv),

authentication.authenticator.basic
authentication.authenticator.basic.parameters
authentication.authenticator.basic.parameters.showAuthFailureReason
authentication.authenticator.basic.parameters.showAuthFailureReasonOnLoginPage
authentication.authenticator.totp
authentication.authenticator.totp.parameters
authentication.authenticator.totp.parameters.showAuthFailureReason
authentication.authenticator.totp.parameters.showAuthFailureReasonOnLoginPage
authentication.authenticator.totp.parameters.encodingMethod
authentication.authenticator.totp.parameters.timeStepSize

Di sini, kerana terdapat banyak perkataan berulang yang serupa dalam ruangan basictotp 字段 parameters 重复,因此脚本会混淆自身并生成两个 totpparameters 结构。预期结果是具有 basicparameterstotpparameters 结构。 csv 的 yaml_key.

Saya tahu ini ada kaitan dengan indeks yang dikodkan keras kepada 1 dalam go_var = selected_rows['go_var'].values[1] tetapi sukar untuk membetulkannya.

Bolehkah seseorang menunjukkan saya kepada jawapan? Saya rasa,

  1. Masalah dengan fungsi rekursif
  2. Terdapat masalah dengan kod yang menjana json mungkin punca kepada isu ini.

Terima kasih!

Saya juga cuba menggunakan chatgpt, tetapi kerana ini ada kaitan dengan nesting dan rekursi, jawapan yang diberikan oleh chatgpt tidak begitu cekap.

Dikemas kini

Saya menjumpai pendua dalam lajur yang mengandungi propertiespooloptionsendpointparameters 字段的行存在问题。这是因为它们在 yaml_key.

Penyelesaian

Saya dapat menyelesaikan masalah ini. Walau bagaimanapun, saya terpaksa menggunakan pendekatan yang benar-benar baru untuk masalah itu, iaitu menggunakan struktur data pokok dan kemudian mengulanginya. Ini adalah logik utama di sebaliknya - https://www.geeksforgeeks.org/level-sequential tree traversal/

Ini ialah kod python yang berfungsi.

import pandas as pd
from collections import deque

structs=[]
class TreeNode:
    def __init__(self, name):
        self.name = name
        self.children = []
        self.path=""

    def add_child(self, child):
        self.children.append(child)

def create_tree(data):
    root = TreeNode('')
    for item in data:
        node = root
        for name in item.split('.'):
            existing_child = next((child for child in node.children if child.name == name), None)
            if existing_child:
                node = existing_child
            else:
                new_child = TreeNode(name)
                node.add_child(new_child)
                node = new_child
    return root

def generate_go_struct(struct_data):
    struct_name = struct_data['struct_name']
    fields = struct_data['fields']
    
    go_struct = f"type {struct_name} struct {{\n"

    for field in fields:
        field_name = field['name']
        field_type = field['type']
        field_default_val = str(field['default_val'])
        json_key=field['json_key']
        toml_key=field['toml_key']

        tail_part=f"\t{field_name} {field_type} `json:\"{json_key},omitempty\" toml:\"{toml_key}\"`\n\n"

        if pd.isna(field['default_val']):
            go_struct += tail_part
        else:
            field_default_val = "\t// +kubebuilder:default:=" + field_default_val
            go_struct += field_default_val + "\n" + tail_part

    go_struct += "}\n\n"
    return go_struct

def write_go_file(go_structs, file_path):
    with open(file_path, 'w') as file:
        for go_struct in go_structs:
            file.write(go_struct)

def create_new_struct(struct_name):
    struct_name = "Configurations" if struct_name == "" else struct_name
    struct_dict = {
        "struct_name": struct_name,
        "fields": []
    }
    
    return struct_dict

def add_field(struct_dict, field_name, field_type,default_val,json_key, toml_key):
    field_dict = {
        "name": field_name,
        "type": field_type,
        "default_val": default_val,
        "json_key":json_key,
        "toml_key":toml_key
    }
    struct_dict["fields"].append(field_dict)
    
    return struct_dict

def traverse_tree(root):
    queue = deque([root])  
    while queue:
        node = queue.popleft()
        filtered_df = df[df['yaml_key'] == node.path]
        go_var = filtered_df['go_var'].values[0] if not filtered_df.empty else None
        go_type = filtered_df['go_type'].values[0] if not filtered_df.empty else None

        if node.path=="":
            go_type="Configurations"

        # The structs themselves
        current_struct = create_new_struct(go_type)
        
        for child in node.children:  
            if (node.name!=""):
                child.path=node.path+"."+child.name   
            else:
                child.path=child.name

            filtered_df = df[df['yaml_key'] == child.path]
            go_var = filtered_df['go_var'].values[0] if not filtered_df.empty else None
            go_type = filtered_df['go_type'].values[0] if not filtered_df.empty else None
            default_val = filtered_df['default_val'].values[0] if not filtered_df.empty else None

            # Struct fields
            json_key = filtered_df['yaml_key'].values[0].split('.')[-1] if not filtered_df.empty else None
            toml_key = filtered_df['toml_key'].values[0].split('.')[-1] if not filtered_df.empty else None
            
            current_struct = add_field(current_struct, go_var, go_type,default_val,json_key, toml_key)

            if (child.children):
                # Add each child to the queue for processing
                queue.append(child)

        go_struct = generate_go_struct(current_struct)
        # print(go_struct,"\n")        
        structs.append(go_struct)

    write_go_file(structs, "output.go")

csv_file = "~/Downloads/my_configs.csv"
df = pd.read_csv(csv_file) 

sample_data=df['yaml_key'].values.tolist()

# Create the tree
tree = create_tree(sample_data)

# Traverse the tree
traverse_tree(tree)

Terima kasih banyak atas bantuan anda!

Atas ialah kandungan terperinci Tukar nilai yang dipisahkan titik kepada struct Go menggunakan Python. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:stackoverflow.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam