`
cjf068
  • 浏览: 34421 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

行文件分组统计

 
阅读更多
有些情况下,对于一个结构化的以行为记录的文本文件,需要按列分组统计,如果数据量小,可以直接导入数据库中,但是当文件很大时,导入数据库不太现实,本程序即实现非数据库条件下,按任意列分组统计行数功能;文件只读一次,按任意分组方式查询。

基本思路:
1.根据指定的列名,构建一颗多叉树,树的高度即为可以分组的条件列数
2.存储树中,各节点名按字典顺序降序排列
3.查询时,根据指定的列名,找到对应的树节点,将其中value值累加返回
以下为第一个初级版本,欢迎指点!!

树节点:
package org.jf.sta;

import java.util.ArrayList;
import java.util.List;

public class SegNode 
{
	private String name;
	private String id;
	private int value;
	private List<SegNode> childList;
	
	public SegNode()
	{
		childList = new ArrayList<SegNode>();
	}
	
	public SegNode(String name,String id)
	{
		this();
		this.name = name;
		this.id = id;
//		childList = new ArrayList<SegNode>();
	}
	public String getName() {
		return name;
	}

	public String getId() {
		return id;
	}
	
	public int getValue() {
		return value;
	}
	public void setValue(int value) {
		this.value = value;
	}
	
	public void addValue(int increment)
	{
		this.value += increment;
	}

	public List<SegNode> getChildList()
	{
		return this.childList;
	}
	
	public void addChild(SegNode node)
	{
		this.childList.add(node);
	}
	
	public String toXml()
	{
		
		String s="<"+name+" id=\""+this.id+"\" value=\""+this.value+"\">\n";
		for(int i=0;i<this.childList.size();i++)
		{
			s = s+childList.get(i).toXml(" ");
		}
		s+="</"+name+">\n";
		return s;
	}
	
	public String toXml(String blank)
	{
		String s="";
		if(childList.size()==0)
		{
			s=blank+"<"+name+" id=\""+this.id+"\" value=\""+this.value+"\"/>\n";
		}else
		{
			s=blank+"<"+name+" id=\""+this.id+"\" value=\""+this.value+"\">\n";
			for(int i=0;i<this.childList.size();i++)
			{
				s = s+blank+childList.get(i).toXml(blank+" ");
			}
			s+=blank+"</"+name+">\n";
		}
		
		return s;
	}
}


统计树
package org.jf.sta;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;


/**
 * 行文件统计工具类
 * 行文件 :每行一条记录  字段间用分隔符 默认为一到多个空白字符 
 * 
 * 一次读取,任意分组
 * 
 * @author junfeng.chen
 *
 */
public class LineStaTree {
	
    private SegNode root;
    private Map<String,Integer> internalColumnMap;
    private String[] columnNames;
    private Map<String,Integer> columnMap;
	private String seprator="\\s+";
	
	
	public LineStaTree(Map<String,Integer> column_map)
	{
		this.columnMap = column_map;
		this.columnNames = new String[column_map.size()];
		int i=0;
		for(String column_name:column_map.keySet())
		{
			columnNames[i++]=column_name;
		}
		Arrays.sort(columnNames);
		internalColumnMap = new HashMap<String,Integer>();
		root = new SegNode();
		for(i=0;i<columnNames.length;i++)
		{
			internalColumnMap.put(columnNames[i], i);
		}
		
	}
	
	public void load(InputStream is)
	{
		BufferedReader br = null;
		try{
			br = new BufferedReader(new InputStreamReader(is));
			String str = br.readLine();
			while(str!=null)
			{
				addLine(str);
			}
		}catch(IOException e)
		{
			e.printStackTrace();
		}
		
	}
	
	public void load(File file)
	{
		InputStream is;
		try {
			if(!file.exists()||file.isDirectory())
				throw new RuntimeException("illegle argumet");
			is = new FileInputStream(file);
			this.load(is);
			is.close();
		} catch (Exception e) 
		{
			e.printStackTrace();
		}
	
	}
	
	public void setSeprator(String sep)
	{
		seprator = sep;
	}
	
	public void addLine(String line)
	{
		String ss[] = line.split(seprator);
		if(ss.length<columnNames.length)
			return;
		root.addValue(1);
		this.add(root, ss, 0);
	}
	
	private void add(SegNode parent,String []ss,int column_index)
	{
		
		List<SegNode> nodeList = parent.getChildList();
		String columnName = columnNames[column_index];
		int index = columnMap.get(columnName);
		String id=ss[index];
		SegNode node = null;
		if(nodeList.size()==0)
		{
		    node = new SegNode(columnName,id);
			node.addValue(1);
			nodeList.add(node);
		}else
		{
			for(int i=0;i<nodeList.size();i++)
			{
				node = nodeList.get(i);
				if(id!=null)
				{
					if(id.equals(node.getId()))
						break;
				}
			}
			if(node==null||!id.equals(node.getId()))
			{
				node = new SegNode(columnName,id);
				nodeList.add(node);
			}
			node.addValue(1);
			
		}
	
		if(column_index==columnNames.length-1)
			return;
		
		add(node,ss,column_index+1);
	}
	
	
	/***
	 * 1.计算出起始节点的层序号和终点节点的层序号 start end
	 * 2.移动到第一个统计节点
	 * 3.遍历 end-start次
	 * 4.获取末节点id 与首节点id组成串 put进hashmap
	 * 
	 * 
	 * 
	 */
	
	//获取第 n 层子节点
	private List<SegNode> getChildList(SegNode parent,int count,List<SegNode> list)
	{
		if(list==null)
			list = new ArrayList<SegNode>();
		{
			List<SegNode> sonList = parent.getChildList();
			if(count<=0)
			{
				list.addAll(sonList);
			}else
			{
				SegNode node = null;
				for(int i=0;i<sonList.size();i++)
				{
					node = sonList.get(i);
					getChildList(node,count-1,list);
				}
			}
		}
		return list;
	}
	
	//移动到末节点的路径 Map<String,Integer> //id1$$id2$$id3 然后将对应位置的id置为空字符串
	//相同key的数据累加
	//获取首节点列表
	//获取末节点列表
	//从首节点开始遍历,直到end结束  记录id组成的路径 
	private Map<String,Integer> getCount(int  begin,int end,String []columns)
	{
		List<SegNode> beginList = this.getChildList(root, begin, null);
		SegNode beginNode = null;
		Map<String,Integer> result_map = new HashMap<String,Integer>(); 
		if(begin==end)
		{
			for(int i=0;i<beginList.size();i++)
			{
				beginNode = beginList.get(i);
				Integer intg = result_map.get(beginNode.getId());
				if(intg==null)
					intg = new Integer(beginNode.getValue());
				else
					intg=intg+beginNode.getValue();
				result_map.put(beginNode.getId(), intg);
			}
			return result_map;
		}
		for(int i=0;i<beginList.size();i++)
		{
			beginNode = beginList.get(i);
			travle(beginNode, end-begin, beginNode.getId(), result_map,columns);
		}
		return result_map;
	}
	
	public Map<String,Integer> groupBy(String[] columns)
	{
		if(columns==null||columns.length==0)
		{
			Map<String,Integer> map = new HashMap<String,Integer>();
			map.put("*", root.getValue());
			return map;
		}
		Arrays.sort(columns);
		int startIndex = this.internalColumnMap.get(columns[0]);//节点层 序号
		int endIndex = this.internalColumnMap.get(columns[columns.length-1]);
		
		String queryColumns[] = new String[this.columnNames.length];
		for(int i=0;i<columnNames.length;i++)//全部置为*
		{
			queryColumns[i]="*";
		}
		for(int i=0;i<columns.length;i++)//将本次查询的条件列 置入其中
		{
			queryColumns[this.internalColumnMap.get(columns[i])]=columns[i];
		}
		String queryColumns2 [] = new String[endIndex-startIndex+1];
		System.arraycopy(queryColumns, startIndex, queryColumns2, 0, queryColumns2.length);
		Map<String,Integer> result = this.getCount(startIndex, endIndex, queryColumns2);
		return result;
	}
	
	
	/**
	 * 
	 * @param beginNode
	 * @param steps
	 * @param path
	 * @param map
	 * @param columns
	 * @return
	 */
	private  Map<String,Integer> travle(
										SegNode beginNode,
										int steps,
										String parentpath,
										Map<String,Integer> map,
										String [] columns)
	{
		if(parentpath==null)
			parentpath="";
		if(map==null)
			map = new HashMap<String,Integer>();
		if(steps<=1)
		{
			List<SegNode> list = beginNode.getChildList();
			SegNode node = null;
			for(int i=0;i<list.size();i++)
			{
				node = list.get(i);
				String path = parentpath;
				if(columns[columns.length-steps].equals("*"))
					path = path+"_*";//提前设置 跨层节点为空
				else
					path = path+"_"+node.getId();
				Integer intg = map.get(path);
				if(intg!=null)
					intg=intg+node.getValue();
				else
					intg = new Integer(node.getValue());
				
				map.put(path, intg);
			}
			
		}else 
		{
			List<SegNode> list = beginNode.getChildList();
			SegNode node = null;
			String path = parentpath;
			for(int i=0;i<list.size();i++)
			{
				node = list.get(i);
				if(columns[columns.length-steps].equals("*"))
					map = travle(node, steps-1, path+"_*", map,columns);
				else
					map = travle(node, steps-1, path+"_"+node.getId(), map,columns);
			}
		}
		return map;
	}
	
	
	
	public String toXml()
	{
		String s="<records id=\"*\" value=\""+root.getValue()+"\">\n";
		List<SegNode> list = root.getChildList();
		for(int i=0;i<list.size();i++)
		{
			s+=list.get(i).toXml(" ");
		}
		s+="</records>\n";
		return s;
	}
	
	public static void main(String args[])
	{
		String ss[] = new String[]{
		 "abc 123 234",
		 "bcd 123 234",
		 "abc 123 345",
		 "abc 123 456",
		 "bcd 123 345",
		 "bcdd 1d23 3s45",
		};
		Map<String,Integer> map = new HashMap<String,Integer>();
		map.put("tag1", 0);
		map.put("tag2", 1);
		map.put("tag3", 2);
		LineStaTree tree = new LineStaTree(map);
		for(String s:ss)
		{
			tree.addLine(s);
		}
		Map<String,Integer> map1 = tree.groupBy(new String[]{"tag1","tag2"});//tree.getCount(0,0,new String[]{"tag1"});
		System.out.println(map1.size());
		Set<String> keys = map1.keySet();
		for(String key:keys)
		{
			System.out.println(key+": "+map1.get(key));
		}
		System.out.println(tree.toXml());
		System.out.println(tree.getChildList(tree.root, 2, null).size());
		
	}
	
	
	
}

分享到:
评论

相关推荐

    微软rdlc报表创建、设置数据、设置分组、分组统计

    **四、分组统计** 1. **总计和平均值**:在分组内,可以添加总计(Sum)和平均值(Average)等统计函数。右键点击分组栏,选择"添加总计",然后选择所需的聚合函数。 2. **自定义计算**:如果默认的统计函数无法...

    MLDN魔乐科技JAVA培训_Oracle课堂10_组函数、分组统计.rar

    视频文件"MLDN魔乐科技JAVA培训_Oracle课堂10_组函数、分组统计.wmv"应该是这个教学内容的详细讲解,涵盖了理论知识和实践案例。 6. **实际应用**:掌握这些技能对于数据库管理员、数据分析师以及任何需要处理大量...

    java读取excel文件,并绘制统计图分析excel内的成绩分布情况

    本教程将介绍如何使用Apache POI库来处理Excel文件,并结合JFreeChart库绘制统计图,以便对成绩分布进行可视化分析。 Apache POI是Java社区开发的一个开源库,它提供了API来读写Microsoft Office格式的文件,包括...

    Python数据可视化(处理地下车库情况的CSV文件,统计信息并绘图)

    此资源充分使用了Python的pandas库来进行CSV文件和Excel文件的处理工作,包括数据分组、排序、导出、插入等。绘制柱状图时不仅需要使用pandas库,还需要matplotlib库,前者用来做数据处理,后者用来做图像的展示和...

    sql 分组,统计等常用语句

    根据给定文件中的标题、描述、标签以及部分内容,本文将详细介绍SQL中分组与统计相关的常用语句及其应用场景。这不仅包括基本的分组查询、条件筛选,还涉及到了更高级的功能,如聚合函数的使用、ROLLUP和CUBE的区别...

    DataGridView 合计行

    标题中的"DataGridView 合计行"是指一种技术手段,用于在`DataGridView`的最后一行显示各种统计计算结果,比如列的总和、平均值、最大值和最小值。这种功能对于数据分析和报告展示非常有用,可以帮助用户快速了解...

    gridcontrol实现分组,并实现分组总计,平均统计

    在GridControl中,我们可以设置列的分组规则,根据特定字段对数据行进行自动分组。 接着,我们来看看如何在GridControl中实现分组。这通常涉及到以下步骤: 1. **配置GridControl**:首先,确保你已经在设计界面...

    RDLC分组报表示例

    5. **分组头部和尾部**:分组后,RDLC会自动添加分组头部和尾部,你可以自定义这些部分的内容,如显示分组的总计、平均值等统计信息。 6. **编译和运行**:完成设计后,保存报表并编译解决方案("分组报表.sln"),...

    多表分组统计C#源码实例

    本文将通过一个实例,探讨如何实现多表分组统计的功能。标题“多表分组统计C#源码实例”暗示我们将讨论如何使用C#处理多个关联的数据表,并进行复杂的统计操作。 首先,我们要了解C#中的数据库访问技术。最常用的是...

    在DataGridView底部实现统计行

    3. **自定义控件**:如果你需要更复杂的统计功能,比如条件计算或分组统计,可以考虑创建一个自定义的`DataGridView`控件,重写其部分方法来插入和更新统计行。 4. **模板列**:使用`DataGridViewTemplateColumn`,...

    es从行json文件中查询相关内容

    5. **分组聚合**:使用`aggregations` 功能对结果进行分组统计,如求平均值、计数等。 例如,以下查询语句将从`your_index_name`索引中找出`message`字段包含“example”的文档: ```json { "query": { "match": ...

    SQL学习实例文件

    1. **SELECT语句**:用于从数据库中检索数据,可以配合WHERE子句进行条件筛选,ORDER BY子句进行排序,GROUP BY和HAVING子句进行分组统计。 2. **INSERT语句**:用于向数据库表中插入新的数据行。 3. **UPDATE语句...

    参照filelist表获取文件

    `svn2.ps1`可能是一个PowerShell脚本,设计用于自动化处理`svn.log`文件,例如,提取数据并进行分组统计。PowerShell是一种强大的命令行接口,常用于系统管理和自动化任务,对于这种数据分析任务非常适用。 `add....

    商品列表的CSV文件

    # 根据类别ID分组统计商品数量 category_counts = products.groupby('categoryID')['商品ID'].count() print(category_counts) ``` 通过这样的分析,我们可以获取关于商品分布和类别流行度的见解,从而更好地优化...

    源码统计器源代码

    可能还需要按文件、目录或整个项目级别进行分组统计。 5. **结果展示**:将统计结果以用户友好的形式展示,比如命令行输出、文本报告或者图形界面。可能包含总行数、代码行数、注释行数和空白行数的百分比等信息。 ...

    -分组函数&子查询

    #### 分组统计 当需要根据特定列进行分组并应用组函数时,使用`GROUP BY`子句。 - 范例:`SELECT deptno, COUNT(*) FROM emp GROUP BY deptno;` — 按部门编号分组,计算每个部门的员工数量。 - 范例:`SELECT ...

    java 从hadoop hdfs读取文件 进行groupby并显示为条形图

    6. **统计函数计算**:对于COUNT,可以直接统计分组内的元素数量;AVG需要先累加所有值,然后除以元素个数;MAX则需要保持当前最大值。这些操作可以在Reduce阶段完成。 7. **图形界面**:为了将统计结果可视化,...

    Reporting service 报表展示分组实例

    8. **汇总和总计**: Reporting Service提供了内置的聚合函数(如SUM, AVG等),可以在分组级别上计算总和或其他统计信息。 9. **参数和交互性**: 为了提高报表的灵活性,我们可以添加参数让用户选择要查看的特定...

    学生成绩统计分析排名

    此外,也可能需要进行分组统计,比如按班级或科目分组。 5. **排名**:基于学生的成绩,程序需要生成排名。这涉及到排序算法的应用,例如快速排序、归并排序或冒泡排序,将学生按照成绩由高到低排列。 6. **界面...

    excel分组小程序

    在Excel中,分组是一种常用的数据分析方法,它允许用户依据某一或多个列的值将数据行聚集在一起,以便于比较和分析。这款小程序进一步扩展了这一功能,特别是在处理非标准或大规模数据集时,它能避免手动操作带来的...

Global site tag (gtag.js) - Google Analytics