如何在C#中的通用列表中找到重复的顺序条目?

时间:2011-01-19 21:04:38

标签: c# linq list

我有一些我要处理的标记文件。

文件中的每一行都具有以下格式(为清晰起见而格式化):

Name1     Tag1     Origin1  
Name2     Tag2     Origin2  

我需要一个执行以下操作的C#解决方案:

  1. 获取名称出现的标记,来源和行号。
  2. 查看两个或多个连续名称是否具有相同的标记。如果是这样,请将它们合并。
  3. 为了做到这一点,我尝试了以下代码:

    var line_token = new List<object_tag>();
    line_token.Add(new object_tag 
    { file_name = filename, 
      line_num = line_number, 
      string_name = name, 
      string_tag = tag, 
      string_origin = origin
    });
    

    ListArrayList获取其输入值。

    示例输入:

    item[0]:  
    file_name:"test1.txt"  
    line_num:1  
    string_name:Asia  
    string_tag:NP  
    string_origin:<unknown>
    

    有没有办法根据string_tag搜索此列表,并查找一行中的两个或多个项目是否具有相同的string_tag,如果是,则将它们合并为一个新项目?


    更新:让我发布一些代码以使问题更加清晰..

    用这个我创建文件列表..

     private  static List <object_tag> tagged_line_list()
        {
            string input = "C:Desktop\\_tagged\\";
            string line;
            string[] files;
    
            int j = 0;
    
    
            if (System.IO.Directory.Exists(input) == false)
            {
    
                Console.WriteLine("The file doesn't exist");
            }
            //take the folder's files
            files = System.IO.Directory.GetFiles(input);
            //create new list with type object_tag
            var line_token = new List<object_tag>();
            //delete the contents of the list
            line_token.Clear();
    
            //create an array list 
            ArrayList tokens = new ArrayList();
            tokens.Clear();
    
            foreach (string file in files)
            {
                string filename = System.IO.Path.GetFileNameWithoutExtension(file);
                int line_number = 1;
                //read the files
                StreamReader sr = new StreamReader(file);
    
                while ((line = sr.ReadLine()) != null)
                {
                    string input_line = line;
                    char[] delimiters = { '\t' };
                    //split the line in words
                    string[] words = input_line.Split(delimiters);
                    //add each word to the token array_list
                    foreach (string word in words)
                    {
                        tokens.Add(word);
                    }
    
                    string name = tokens[j+ 0] as string;
                    string tag = tokens[j + 1] as string;
                    string origin = tokens[j + 2] as string;
    
                   //add to the line-token list instances
                    line_token.Add(new object_tag{file_name=filename,line_num=line_number,string_name=name,string_tag=tag,string_origin=origin});
    
                    j = j + 3; 
                    line_number++;
                }
    
                sr.Close();
            }
            //returns the line_token list
            return line_token;   
        }
    

    接下来我想在列表中搜索执行该操作的代码

    private static List<object_tag> search_list()
        {
            //calls the tagged_line_list method for retrieving the line-token list
            var line_token = tagged_line_list();
            object_tag last = null;
            List<object_tag> du_np = new List<object_tag>();
            du_np.Clear();
            List<object_tag> list_np_query = new List<object_tag>();
            list_np_query.Clear();
    
    
              var np_query =
                from i in line_token
                where ((i.string_tag == "NP" | i.string_tag == "NPS"))
                select i;
            //create new list which contains instances with string_tag NP or NPS
              list_np_query = np_query.ToList<object_tag>();
    
              for (int i = 0; i < list_np_query.Count; i++)
              {
                  if (last == null)
                  {
                      last = list_np_query[i];
    
                  }
                  else if (
                      //the objects are in the same file
                      (last.file_name == list_np_query[i].file_name)
                      &
                      //the objects are consecutive
                      (list_np_query[i].line_num - last.line_num == 1)
    
                      )
                  {
    
    
                      last.file_name = list_np_query[i - 1].file_name;
                      last.line_num = list_np_query[i - 1].line_num;
                      last.string_name = last.string_name + " " + list_np_query[i].string_name;
                      last.string_tag = list_np_query[i - 1].string_tag;
                      last.string_origin = "<unknown>";
    
                      du_np.Add(last);
    
                  }
                  else
                  {
                      last = list_np_query[i];
    
                  }
              }
    
                return (du_np);
        }
    

    现在我有一个名为list_np_query的列表,它只包含带有string_tag NP或NPS的对象。如果对象在连续的行中并且具有相同的文件名,我会将它们放在名为du_np的新列表中。解决方案在我面前,但我没有看到它...... 无论如何,感谢大家的帮助和时间!!!!!

4 个答案:

答案 0 :(得分:0)

你能用词典代表吗?通过字典,您可以根据非数字值跟踪信息。我不确定这是否适合您的申请。

var items = new Dictionary<string, object_tag>();

foreach(item in itemArray)
{
    if(items.ContainsKey(item.string_tag))
    {
        //do your combining stuff and store in items[item.string_tag]
    }
    else
    {
        items.add(item.string_tag, new object_tag{/*blablablah*/});
    }
}

答案 1 :(得分:0)

您还可以编写一个for循环,展望未来,并在项目满足您的需求时返回。像:

IEnumerable<object_tag> CombineDuplicates(ArrayList source)
{
  object_tag last = null;
  for (int i=0;i<source.Count;i++)
  {
   if (last == null) 
   {
     last = source[i];
   }
   else if (last.string_tag == source[i].string_tag)
   {
      last.Combine(source[i]);
   }
   else 
   {
      yield return last;
      last = source[i];
   }
  }
  yield return last;
}

然后你可以打电话

foreach (var item in CombineDuplicates(input))
{
   //do whatever you want
}

不是说它是唯一的解决方案,但C#有很多种口味...... :) (你可以用一个List替换IEnumerable,在函数的开头创建一个新的List而不是让它们产生,你可以将它们添加到列表中,并在最后返回列表。选择最适合你需要的列表。 ..)

答案 2 :(得分:0)

如果通过“合并”意味着删除重复记录,那么我有一个linq解决方案。

var results =
    (from lt in line_token
    orderby lt.line_num
    group lt by lt.string_tag into glts
    let dups = glts
        .Skip(1)
        .Zip(glts, (lt1, lt0) => new
            {
                lt1,
                delta = lt1.line_num - lt0.line_num
            })
        .Where(x => x.delta == 1)
        .Select(x => x.lt1)
    select glts.Except(dups))
        .SelectMany(x => x)
        .OrderBy(x => x.line_num);

它不是很漂亮,但确实有用。

答案 3 :(得分:-1)

我会使用列表&lt;&gt;在这里你可以传递许多变量到这个&lt;&gt;部分。所以例如;

 list<string, int> item = new list()<string,int>;

然后您可以使用

添加项目
  item.Add(); 

方法。它将支持诸如

之类的方法
 if(item.Contains())

如果这不是你想要的,请告诉我。很抱歉,但请注意,发布时应更好地格式化代码。我很难读它,不得不复制并粘贴到记事本并重新格式化。只是未来发布的注释。