本文目录导读:

我来为您提供一个Java案例,统计长短传比例分布,这里我提供两种实现方式:
基础版本 - 简单的比例统计
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
public class PassAnalysis {
// 传球类型枚举
public enum PassType {
SHORT_PASS("短传", 0, 15), // 0-15米
MEDIUM_PASS("中传", 15, 30), // 15-30米
LONG_PASS("长传", 30, 60); // 30-60米
private String displayName;
private int minDistance;
private int maxDistance;
PassType(String displayName, int minDistance, int maxDistance) {
this.displayName = displayName;
this.minDistance = minDistance;
this.maxDistance = maxDistance;
}
public String getDisplayName() {
return displayName;
}
public static PassType classify(int distance) {
for (PassType type : values()) {
if (distance >= type.minDistance && distance < type.maxDistance) {
return type;
}
}
return LONG_PASS; // 超长传视为长传
}
}
// 传球数据类
public static class Pass {
private int playerId;
private int distance;
private PassType type;
public Pass(int playerId, int distance) {
this.playerId = playerId;
this.distance = distance;
this.type = PassType.classify(distance);
}
public int getPlayerId() { return playerId; }
public int getDistance() { return distance; }
public PassType getType() { return type; }
}
// 统计结果类
public static class PassStatistics {
private int totalPasses;
private Map<PassType, Integer> passCountMap;
private Map<PassType, Double> passPercentageMap;
public PassStatistics(List<Pass> passes) {
passCountMap = new HashMap<>();
totalPasses = passes.size();
// 初始化计数器
for (PassType type : PassType.values()) {
passCountMap.put(type, 0);
}
// 统计各类传球数量
for (Pass pass : passes) {
passCountMap.merge(pass.getType(), 1, Integer::sum);
}
// 计算百分比
passPercentageMap = new HashMap<>();
for (PassType type : PassType.values()) {
int count = passCountMap.get(type);
double percentage = totalPasses > 0 ?
(count * 100.0 / totalPasses) : 0.0;
passPercentageMap.put(type, percentage);
}
}
public void printStatistics() {
System.out.println("=== 传球统计报告 ===");
System.out.printf("总传球次数: %d%n", totalPasses);
System.out.println("-------------------");
System.out.println("传球类型 | 数量 | 占比");
for (PassType type : PassType.values()) {
int count = passCountMap.getOrDefault(type, 0);
double percentage = passPercentageMap.getOrDefault(type, 0.0);
System.out.printf("%-6s | %4d | %.2f%%%n",
type.getDisplayName(), count, percentage);
}
System.out.println("-------------------");
// 显示可视化分布
printDistributionChart();
}
// 可视化分布图
private void printDistributionChart() {
System.out.println("分布可视化:");
for (PassType type : PassType.values()) {
int count = passCountMap.getOrDefault(type, 0);
int barLength = (int) Math.round(count * 30.0 / totalPasses);
String bar = "█".repeat(Math.max(barLength, 1));
System.out.printf("%-6s | %s (%d次)%n",
type.getDisplayName(), bar, count);
}
}
}
// 测试方法
public static void main(String[] args) {
// 模拟示例:生成随机传球数据
List<Pass> passes = generateRandomPasses(100);
// 创建统计对象
PassStatistics stats = new PassStatistics(passes);
// 输出统计结果
stats.printStatistics();
// 额外:按球员统计
Map<Integer, List<Pass>> playerPasses = groupByPlayer(passes);
System.out.println("\n=== 球员传球统计 ===");
for (Map.Entry<Integer, List<Pass>> entry : playerPasses.entrySet()) {
int playerId = entry.getKey();
List<Pass> playerPassList = entry.getValue();
System.out.printf("球员 %d: 共%d次传球%n", playerId, playerPassList.size());
}
}
// 生成随机传球数据
private static List<Pass> generateRandomPasses(int count) {
List<Pass> passes = new ArrayList<>();
Random random = new Random();
for (int i = 0; i < count; i++) {
int playerId = random.nextInt(10) + 1; // 假设10名球员
int distance = random.nextInt(70); // 0-69米
passes.add(new Pass(playerId, distance));
}
return passes;
}
// 按球员分组
private static Map<Integer, List<Pass>> groupByPlayer(List<Pass> passes) {
Map<Integer, List<Pass>> grouped = new HashMap<>();
for (Pass pass : passes) {
grouped.computeIfAbsent(pass.getPlayerId(), k -> new ArrayList<>())
.add(pass);
}
return grouped;
}
}
进阶版本 - 支持数据导入和多种统计维度
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;
public class AdvancedPassAnalysis {
// 传球统计数据模型
public static class PassData {
private int matchId;
private int playerId;
private double startX, startY; // 起始位置
private double endX, endY; // 结束位置
private int distance; // 传球距离
public PassData(int matchId, int playerId,
double startX, double startY,
double endX, double endY) {
this.matchId = matchId;
this.playerId = playerId;
this.startX = startX;
this.startY = startY;
this.endX = endX;
this.endY = endY;
this.distance = calculateDistance();
}
private int calculateDistance() {
// 欧几里得距离计算
return (int) Math.sqrt(
Math.pow(endX - startX, 2) + Math.pow(endY - startY, 2)
);
}
public int getDistance() { return distance; }
public int getPlayerId() { return playerId; }
public int getMatchId() { return matchId; }
}
// 统计聚合器
public static class StatisticsAggregator {
private List<PassData> allPasses;
public StatisticsAggregator(List<PassData> passes) {
this.allPasses = passes;
}
// 按距离区间统计
public Map<String, Double> getDistanceDistribution() {
Map<String, Integer> countMap = new LinkedHashMap<>();
countMap.put("极短传(0-5m)", 0);
countMap.put("短传(5-15m)", 0);
countMap.put("中传(15-25m)", 0);
countMap.put("长传(25-40m)", 0);
countMap.put("超长传(40m以上)", 0);
for (PassData pass : allPasses) {
int dist = pass.getDistance();
String category = categorizeDistance(dist);
countMap.merge(category, 1, Integer::sum);
}
Map<String, Double> percentageMap = new LinkedHashMap<>();
int total = allPasses.size();
countMap.forEach((key, value) -> {
percentageMap.put(key, total > 0 ? (value * 100.0 / total) : 0.0);
});
return percentageMap;
}
private String categorizeDistance(int distance) {
if (distance <= 5) return "极短传(0-5m)";
if (distance <= 15) return "短传(5-15m)";
if (distance <= 25) return "中传(15-25m)";
if (distance <= 40) return "长传(25-40m)";
return "超长传(40m以上)";
}
// 按比赛统计
public Map<Integer, Map<String, Double>> getMatchStats() {
Map<Integer, List<PassData>> matchGroups = allPasses.stream()
.collect(Collectors.groupingBy(PassData::getMatchId));
Map<Integer, Map<String, Double>> result = new HashMap<>();
for (Map.Entry<Integer, List<PassData>> entry : matchGroups.entrySet()) {
StatisticsAggregator subAgg = new StatisticsAggregator(entry.getValue());
result.put(entry.getKey(), subAgg.getDistanceDistribution());
}
return result;
}
// 计算短长传比例(短传:15m以下, 长传:15m以上)
public double getShortLongRatio() {
int shortPasses = 0;
int longPasses = 0;
for (PassData pass : allPasses) {
if (pass.getDistance() <= 15) {
shortPasses++;
} else {
longPasses++;
}
}
return longPasses > 0 ? (double) shortPasses / longPasses : 0.0;
}
// 生成完整报告
public void generateReport() {
System.out.println("═══════════════════════════════════");
System.out.println(" 传球分析综合报告");
System.out.println("═══════════════════════════════════");
System.out.printf("总传球数: %d%n", allPasses.size());
Map<String, Double> distribution = getDistanceDistribution();
System.out.println("\n距离分布:");
distribution.forEach((category, percentage) -> {
System.out.printf(" %-15s: %.2f%%%n", category, percentage);
});
System.out.printf("%n短传/长传比例: 1 : %.2f%n",
1.0 / getShortLongRatio());
System.out.print("\n柱状图: \n");
for (Map.Entry<String, Double> entry : distribution.entrySet()) {
int barLength = (int)(entry.getValue() / 5); // 5%为1个字符
String bar = "★".repeat(Math.max(barLength, 1));
System.out.printf(" %-15s | %s %.2f%%%n",
entry.getKey(), bar, entry.getValue());
}
}
}
// 数据加载器
public static class DataLoader {
public static List<PassData> loadFromFile(String filePath) {
List<PassData> passes = new ArrayList<>();
try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
String line;
reader.readLine(); // 跳过标题行
while ((line = reader.readLine()) != null) {
try {
String[] parts = line.split(",");
PassData pass = new PassData(
Integer.parseInt(parts[0].trim()),
Integer.parseInt(parts[1].trim()),
Double.parseDouble(parts[2].trim()),
Double.parseDouble(parts[3].trim()),
Double.parseDouble(parts[4].trim()),
Double.parseDouble(parts[5].trim())
);
passes.add(pass);
} catch (NumberFormatException e) {
System.err.println("数据解析错误: " + line);
}
}
} catch (IOException e) {
System.err.println("文件读取失败: " + e.getMessage());
}
return passes;
}
public static List<PassData> generateMockData(int number) {
List<PassData> passes = new ArrayList<>();
Random random = new Random();
for (int i = 0; i < number; i++) {
passes.add(new PassData(
random.nextInt(10) + 1, // matchId
random.nextInt(20) + 1, // playerId
random.nextDouble() * 100, // startX
random.nextDouble() * 50, // startY
random.nextDouble() * 100, // endX
random.nextDouble() * 50 // endY
));
}
return passes;
}
}
public static void main(String[] args) {
// 方式1: 使用模拟数据
System.out.println("=== 模拟数据分析 ===");
List<PassData> mockData = DataLoader.generateMockData(500);
StatisticsAggregator aggregator = new StatisticsAggregator(mockData);
aggregator.generateReport();
// 方式2: 支持从CSV文件导入
// List<PassData> fileData = DataLoader.loadFromFile("passes.csv");
// StatisticsAggregator fileAggregator = new StatisticsAggregator(fileData);
// fileAggregator.generateReport();
}
}
CSV示例数据格式
matchId,playerId,startX,startY,endX,endY 1,5,10.5,25.3,20.8,30.2 1,3,30.2,45.1,35.6,40.5 2,7,50.0,20.0,15.0,35.0 ...
关键特性:
- 多维度统计:按距离分类、按球员、按场次统计
- 可视化输出:使用字符图形展示分布
- 灵活扩展:可添加更多统计维度
- 数据导入:支持CSV文件数据导入
- 比例计算:清楚展示长短传比例分布
这个案例可以用于足球比赛数据分析、传球策略研究等场景,您可以根据实际需求调整距离分类标准和统计维度。