用Golang助力表妹轻松实现自动化办公!(完整代码附后)

2023-12-10
4分钟阅读时长

Hello,大家好,我是lbbniu~

今天有一个有趣的编程需求要分享,这次的灵感来源于我可爱的表妹。简单来说,我们将利用Golang对Excel文件进行批量处理,达到高效自动化办公的目的。

一、具体需求

手上有一系列N个表格,每个表格都有相同的结构,看起来就像这样:

表结构

任务是将所有表中的数据汇总,按照每个人的得分和积分进行合计,然后按总积分排名。在总积分相同的情况下,名次也相同但不是连续的排序。如果总积分和名次都相同,再按总得分降序展示,但不改变排名。

结果如下图所示:

结果展示

二、Golang开发

首先,让我们引入需要的包:

package main

import (
	"fmt"
	"log"
	"path/filepath"
	"sort"

	"github.com/tealeg/xlsx"
)

接下来,获取所有Excel文件的路径:

func getExcelFiles() []string {
	files, err := filepath.Glob("./样例数据/*.xlsx")
	if err != nil {
		log.Fatal(err)
	}
	return files
}

然后,将各表数据合并到主结构体:

// Record 结构体表示每个人的记录
type Record struct {
	Name    string
	Monthly int
	Points  int
	Ranking int
}

func getCellValue(cell *xlsx.Cell) int {
	value, err := cell.Int()
	if err != nil {
		log.Fatal(err)
	}
	return value
}

func mergeData(files []string) []Record {
	var mergedData []Record

	for _, file := range files {
		// 读取Excel文件
		xlFile, err := xlsx.OpenFile(file)
		if err != nil {
			log.Fatal(err)
		}

		// 处理每个Sheet
		for _, sheet := range xlFile.Sheets {
			for _, row := range sheet.Rows[2:] {
				record := Record{
					Name:    row.Cells[0].String(),
					Monthly: getCellValue(row.Cells[1]),
					Points:  getCellValue(row.Cells[3]),
				}
				mergedData = append(mergedData, record)
			}
		}
	}

	return mergedData
}

接下来,计算总积分和总排名:

func calculateTotalAndRanking(data []Record) []Record {
	totalMonthlys := make(map[string]int)
	totalPoints := make(map[string]int)
	uniqueNames := make(map[string]bool)
	var mergedRecords []Record

	for _, record := range data {
		uniqueNames[record.Name] = true
		totalMonthlys[record.Name] += record.Monthly
		totalPoints[record.Name] += record.Points
	}

	sortedNames := make([]string, 0, len(uniqueNames))
	for name := range uniqueNames {
		sortedNames = append(sortedNames, name)
	}

	sort.Slice(sortedNames, func(i, j int) bool {
		if totalPoints[sortedNames[i]] == totalPoints[sortedNames[j]] {
			return sortedNames[i] < sortedNames[j]
		}
		return totalPoints[sortedNames[i]] > totalPoints[sortedNames[j]]
	})

	for _, record := range data {
		if _, ok := uniqueNames[record.Name]; ok {
			mergedRecord := Record{
				Name:    record.Name,
				Monthly: totalMonthlys[record.Name],
				Points:  totalPoints[record.Name],
			}
			mergedRecords = append(mergedRecords, mergedRecord)
			delete(uniqueNames, record.Name) // 避免重复计算相同姓名的记录
		}
	}

	return mergedRecords
}

最后,按总积分和总得分排序,输出结果:

func sortAndOutputResults(data []Record) {
	sort.Slice(data, func(i, j int) bool {
		if data[i].Points == data[j].Points {
			return data[i].Monthly > data[j].Monthly
		}
		return data[i].Points > data[j].Points
	})

	outputFile := "总积分及排名.xlsx"
	xlFile := xlsx.NewFile()
	sheet, err := xlFile.AddSheet("Sorted Results")
	if err != nil {
		log.Fatal(err)
	}

	row := sheet.AddRow()
	row.AddCell().Value = "姓名"
	row.AddCell().Value = "总得分"
	row.AddCell().Value = "总积分"
	row.AddCell().Value = "总排名"

	ranking, points := 1, data[0].Points
	for _, record := range data {
		if points != record.Points {
			ranking++
		}
		row := sheet.AddRow()
		row.AddCell().Value = record.Name
		row.AddCell().SetInt(record.Monthly)
		row.AddCell().SetInt(record.Points)
		row.AddCell().SetInt(ranking)
	}

	if err := xlFile.Save(outputFile); err != nil {
		log.Fatal(err)
	}

	fmt.Printf("排序后的结果已保存到 %s\n", outputFile)
}

func main() {
	excelFiles := getExcelFiles()
	mergedData := mergeData(excelFiles)
	calculateTotalAndRanking(mergedData)
	sortAndOutputResults(mergedData)
}

完整代码:

package main

import (
	"fmt"
	"log"
	"path/filepath"
	"sort"

	"github.com/tealeg/xlsx"
)

// Record 结构体表示每个人的记录
type Record struct {
	Name    string
	Monthly int
	Points  int
	Ranking int
}

func getCellValue(cell *xlsx.Cell) int {
	value, err := cell.Int()
	if err != nil {
		log.Fatal(err)
	}
	return value
}

func getExcelFiles() []string {
	files, err := filepath.Glob("./样例数据/*.xlsx")
	if err != nil {
		log.Fatal(err)
	}
	return files
}

func mergeData(files []string) []Record {
	var mergedData []Record

	for _, file := range files {
		// 读取Excel文件
		xlFile, err := xlsx.OpenFile(file)
		if err != nil {
			log.Fatal(err)
		}

		// 处理每个Sheet
		for _, sheet := range xlFile.Sheets {
			for _, row := range sheet.Rows[2:] {
				record := Record{
					Name:    row.Cells[0].String(),
					Monthly: getCellValue(row.Cells[1]),
					Points:  getCellValue(row.Cells[3]),
				}
				mergedData = append(mergedData, record)
			}
		}
	}

	return mergedData
}

func calculateTotalAndRanking(data []Record) []Record {
	totalMonthlys := make(map[string]int)
	totalPoints := make(map[string]int)
	uniqueNames := make(map[string]bool)
	var mergedRecords []Record

	for _, record := range data {
		uniqueNames[record.Name] = true
		totalMonthlys[record.Name] += record.Monthly
		totalPoints[record.Name] += record.Points
	}

	sortedNames := make([]string, 0, len(uniqueNames))
	for name := range uniqueNames {
		sortedNames = append(sortedNames, name)
	}

	sort.Slice(sortedNames, func(i, j int) bool {
		if totalPoints[sortedNames[i]] == totalPoints[sortedNames[j]] {
			return sortedNames[i] < sortedNames[j]
		}
		return totalPoints[sortedNames[i]] > totalPoints[sortedNames[j]]
	})

	for _, record := range data {
		if _, ok := uniqueNames[record.Name]; ok {
			mergedRecord := Record{
				Name:    record.Name,
				Monthly: totalMonthlys[record.Name],
				Points:  totalPoints[record.Name],
			}
			mergedRecords = append(mergedRecords, mergedRecord)
			delete(uniqueNames, record.Name) // 避免重复计算相同姓名的记录
		}
	}

	return mergedRecords
}

func sortAndOutputResults(data []Record) {
	sort.Slice(data, func(i, j int) bool {
		if data[i].Points == data[j].Points {
			return data[i].Monthly > data[j].Monthly
		}
		return data[i].Points > data[j].Points
	})

	outputFile := "总积分及排名.xlsx"
	xlFile := xlsx.NewFile()
	sheet, err := xlFile.AddSheet("Sorted Results")
	if err != nil {
		log.Fatal(err)
	}

	row := sheet.AddRow()
	row.AddCell().Value = "姓名"
	row.AddCell().Value = "总得分"
	row.AddCell().Value = "总积分"
	row.AddCell().Value = "总排名"

	ranking, points := 1, data[0].Points
	for _, record := range data {
		if points != record.Points {
			ranking++
		}
		row := sheet.AddRow()
		row.AddCell().Value = record.Name
		row.AddCell().SetInt(record.Monthly)
		row.AddCell().SetInt(record.Points)
		row.AddCell().SetInt(ranking)
	}

	if err := xlFile.Save(outputFile); err != nil {
		log.Fatal(err)
	}

	fmt.Printf("排序后的结果已保存到 %s\n", outputFile)
}

func main() {
	excelFiles := getExcelFiles()
	mergedData := mergeData(excelFiles)
	mergedData = calculateTotalAndRanking(mergedData)
	sortAndOutputResults(mergedData)
}

以上就是整个Golang实现的简要流程。虽然代码比较简洁,但相信这会为表妹省去不少时间,嘿嘿!

希望大家也能将Golang这个强大的语言用于工作和生活,提高工作效率,让生活更有趣。

关注我的公众号,后台回复“每天进步一点点”,即可获取完整代码和数据哦!

感谢阅读,我们下期见!

lbbniu 敬上

关注我,共同进步!