ListView не могу правильно поставить условие

205
02 ноября 2018, 02:40

Не могу правильно поставить условие

for (int i = 0; i < file1.Count; i++)
            {
                for (int j = 0; j < file2.Count; j++)
                {
                    // Удаленные строки показываются красным цветом, добавленные - желтым, неизмененные - зеленым.
                    if (file1[i] == file2[j])// НЕ измененая строка - зеленая
                    {
                        ListViewItem li = new ListViewItem();
                        li.ForeColor = Color.Green;
                        li.Text = file1[i];
                        listView1.Items.Add(li);
                        break;
                    }
                    if (file1[i] != file2[j]) // Удаленные строки показываются красным цветом,
                    {
                        ListViewItem li = new ListViewItem();
                        li.ForeColor = Color.Red;
                        li.Text = file1[i];
                        listView1.Items.Add(li);
                        break;
                    }
                    //else if ...// добавленные - желтым,
                }
            }

Удаленные строки показываются красным цветом, добавленные - желтым, неизмененные - зеленым. У меня 2 списка

List<string> file1 = new List<string>();
List<string> file2 = new List<string>();

Я ставлю условие что в file найдена строка как и file2 то зеленым, если нет такой то красным ВОТ только цвет изменяется на первой строчке далее идет все красное, а про измененные даже не знаю

Весь код программы:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace AnalyzerTwoTextFiles
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        List<string> file1 = new List<string>();
        List<string> file2 = new List<string>();
        private void btn_generation_Click(object sender, EventArgs e)
        {
            GetFile1();
            WriteToFile();
            GetFile2();
            listView1.Clear();
            for (int i = 0; i < file1.Count; i++)
            {
                for (int j = 0; j < file2.Count; j++)
                {
                    // Удаленные строки показываются красным цветом, добавленные - желтым, неизмененные - зеленым.
                    if (file1[i] == file2[j])// НЕ измененая строка - зеленая
                    {
                        ListViewItem li = new ListViewItem();
                        li.ForeColor = Color.Green;
                        li.Text = file1[i];
                        listView1.Items.Add(li);
                        break;
                    }
                    if (file1[i] != file2[j]) // Удаленные строки показываются красным цветом,
                    {
                        ListViewItem li = new ListViewItem();
                        li.ForeColor = Color.Red;
                        li.Text = file1[i];
                        listView1.Items.Add(li);
                        break;
                    }
                    //else if ...// добавленные - желтым,
                }
            }
        }
        private List<string> GetFile1()
        {
            file1.Clear();
            using (StreamReader sr = new StreamReader("File1.txt"))
            {
                while (!sr.EndOfStream)
                {
                    string[] s = sr.ReadLine().Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
                    string arStr;
                    arStr = "";
                    for (int i = 0; i<s.Length;i++)
                    {
                        arStr += s[i] + " ";
                    }
                    file1.Add(arStr);
                }
                return file1;
            }
        }
        private void WriteToFile()
        {
            using (FileStream fstream = new FileStream("file2.txt", FileMode.Create, FileAccess.Write))
            {
                using (StreamWriter sw = new StreamWriter(fstream))
                {
                    string strfile2 = textBox1.Text;
                    fstream.Seek(0, SeekOrigin.End);
                    sw.WriteLine(textBox1.Text);
                }
            }
        }
        private List<string> GetFile2()
        {
            file2.Clear();
            using (StreamReader sr = new StreamReader("File2.txt"))
            {
                while (!sr.EndOfStream)
                {
                    string[] s = sr.ReadLine().Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
                    string arStr;
                    arStr = "";
                    for (int i = 0; i < s.Length; i++)
                    {
                        arStr += s[i] + " ";
                    }
                    file2.Add(arStr);
                }
                return file2;
            }
        }
    }
}

Пример как должен выглядеть результат рабочий программы

Ссылка на проект - https://github.com/wargerun/AnalyzerTwoTextFiles/

Answer 1

Первый файл (образец)

Первая строка.
Вторая строка.
Третья строка.

Второй файл

Первая строка.
3-я строка.
Еще одна строка.

Получилось так

Код такой

/// <summary>
/// Строка
/// </summary>
class Line
{
    public enum LineType
    {
        Unchanged, //неизмененная
        Added, //добавленная
        Deleted, //удаленная
    }
    public string Text { get; set; }
    public LineType Type { get; set; }
    public override string ToString()
    {
        return $"{Text} : {Type}";
    }
}
/// <summary>
/// Подсобный класс для сверки строк
/// </summary>
class LineComparer : IEqualityComparer<Line>
{
    public bool Equals(Line x, Line y)
    {
        return x.Text.Equals(y.Text);
    }
    public int GetHashCode(Line obj)
    {
        return obj.Text.GetHashCode();
    }
}
class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("ConsoleAppLinesComparison");
        Console.WriteLine();
        var originFile = @"D:\fileOrigin.txt";
        var otherFile = @"D:\fileOther.txt";
        List<Line> originLines = GetLines(originFile);
        List<Line> otherLines = GetLines(otherFile);
        List<Line> resultLines = CheckLines(originLines, otherLines);
        PrintLines(resultLines);
        Console.ReadKey();
    }
    /// <summary>
    /// Чтение файла в коллекцию строк
    /// </summary>
    /// <param name="file">путь к файлу</param>
    /// <returns></returns>
    private static List<Line> GetLines(string file)
    {
        List<Line> result = new List<Line>();
        try
        {
            foreach (var line in File.ReadAllLines(file))
            {
                result.Add(new Line { Text = line });
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Чтение {file} c ошибкой: {ex.Message}");
        }
        return result;
    }
    /// <summary>
    /// Сверка двух коллекций строк,
    /// простановка соответ. типов строкам.
    /// Возвращает объединенную коллекцию строк
    /// </summary>
    /// <param name="originLines">коллекция образец</param>
    /// <param name="otherLines">коллекция для сверки</param>
    /// <returns>объединенная коллекция строк без повторений</returns>
    private static List<Line> CheckLines(List<Line> originLines, List<Line> otherLines)
    {
        //все строки которых нет в другом файле
        var exceptOriginLines = originLines.Except(otherLines, new LineComparer());
        foreach (var line in exceptOriginLines)
        {
            line.Type = Line.LineType.Deleted;
        }
        //все строки которых нет в оригинальном файле
        var exceptOtherLines = otherLines.Except(originLines, new LineComparer());
        foreach (var line in exceptOtherLines)
        {
            line.Type = Line.LineType.Added;
        }
        //объединенная последовательность (без повторений)
        var unionLines = originLines.Union(otherLines, new LineComparer());
        return unionLines.ToList();
    }
    private static void PrintLines(List<Line> resultLines)
    {
        Console.ForegroundColor = ConsoleColor.Green;
        Console.WriteLine("Неизменные строки");
        Console.ForegroundColor = ConsoleColor.Red;
        Console.WriteLine("Удаленные строки");
        Console.ForegroundColor = ConsoleColor.Yellow;
        Console.WriteLine("Добавленные строки");
        Console.ForegroundColor = ConsoleColor.White;
        Console.WriteLine(new string('=', 20));
        Console.WriteLine();
        foreach (var line in resultLines)
        {
            if (line.Type == Line.LineType.Unchanged)
            {
                Console.ForegroundColor = ConsoleColor.Green;
                Console.WriteLine(line.Text);
            }
            else if (line.Type == Line.LineType.Added)
            {
                Console.ForegroundColor = ConsoleColor.Yellow;
                Console.WriteLine(line.Text);
            }
            else
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine(line.Text);
            }
            Console.ForegroundColor = ConsoleColor.White;
        }
    }
}
Answer 2

Определим результат операции

public class CompareStringResult
{
    public enum ActionType { Deleted, Added, NotChanged };
    public ActionType Action { get; }
    public string Data { get; }
    public CompareStringResult(string data, ActionType action)
    {
        Data = data;
        Action = action;
    }
}

Код для сравнения прост, работает линейное время

public IEnumerable<CompareStringResult> Compare(string[] oldValues, string[] newValues)
{
    var result = new List<CompareStringResult>();
    var allLines = new HashSet<string>(oldValues.Union(newValues));
    var oldSet = new HashSet<string>(oldValues);
    var newSet = new HashSet<string>(newValues);
    foreach (var line in allLines)
    {
        var action = CompareStringResult.ActionType.NotChanged;
        if (oldSet.Contains(line) && !newSet.Contains(line)) action = CompareStringResult.ActionType.Deleted;
        if (!oldSet.Contains(line) && newSet.Contains(line)) action = CompareStringResult.ActionType.Added;
        result.Add(new CompareStringResult(line, action));
    }
    return result;
}

Как проверить

var oldV = Enumerable.Range(0, 10).Select(x=>x.ToString()).ToArray();
var newV = Enumerable.Range(5, 10).Select(x=>x.ToString()).ToArray();
foreach(var r in Compare(oldV, newV))
{
    Console.WriteLine($"{r.Action} - {r.Data}");
}

Вывод

Deleted - 0
Deleted - 1
Deleted - 2
Deleted - 3
Deleted - 4
NotChanged - 5
NotChanged - 6
NotChanged - 7
NotChanged - 8
NotChanged - 9
Added - 10
Added - 11
Added - 12
Added - 13
Added - 14
Answer 3

Добавлю ещё один ответ.

У двух существующих ответов есть плюсы - маленький расход памяти, линейная сложность, но при этом и есть минус - они никак не работают с изначальным порядком строк в исходнике и приёмнике.

Чтобы учитывать этот порядок, можно воспользоваться разными алгоритмами. Я попробую воспользоваться самым простым, что знаю - Расстояние Левенштейна, который мы немного подредактируем под нашу задачу. Сам алгоритм расписан на википедии, повторять его здесь смысла нет.

Итак, что мы в алгоритм изменим:

1) Начнем с того, что расстояние Левенштейна изначально предназначено для символов в тексте. Но мы будем вместо символа в тексте сравнивать строку в наборе строк.

2) Замена одной строки на другую в оригинале считается одной операцией. Но мы будем считать, что это 2 операции (удалить старую строку, добавить новую).

Результат операции будем хранить в следующем классе:

public class CompareStringResult
{
    public enum ActionType { Deleted, Added, Changed, NotChanged };
    public ActionType Action { get; }
    public string OldValue { get; }
    public string NewValue { get; }
    public CompareStringResult(string oldValue, string newValue, ActionType action)
    {
        OldValue = oldValue;
        NewValue = newValue;
        Action = action;
    }
}

Вот и, по сути, все. Приступим!

public IEnumerable<CompareStringResult> Compare(string[] oldValues, string[] newValues)
{
    var board = new int[oldValues.Length + 1, newValues.Length + 1];
    for (var i = 0; i < board.GetLength(0); i++) board[i, 0] = i;
    for (var i = 0; i < board.GetLength(1); i++) board[0, i] = i;
// подготовка таблицы изменений
    for (var i = 1; i < board.GetLength(0); i++)
    {
        for (var j = 1; j < board.GetLength(1); j++)
        {
            var stringsEquals = string.CompareOrdinal(oldValues[i - 1], newValues[j - 1]) == 0;
            var add = (stringsEquals ? 0 : 1);
            board[i, j] = Math.Min(board[i - 1, j - 1] + add * 2, Math.Min(board[i - 1, j] + 1, board[i, j - 1] + 1));
        }
    }

// Идея такая: раз нижний правый угол - наша конечная цель, то, чтобы найти кратчайший путь изменений, нам     придется пройти от конца в начало. Стартуем в нижнем правом углу, заканчиваем в верхнем левом. Но, так как  мы движемся в обратном направлении, то я использовал стек для реверса результата к прямому порядку в конце   функции. 
    var stack = new Stack<CompareStringResult>();
    var ii = board.GetLength(0) - 1;
    var jj = board.GetLength(1) - 1;
    // прогулка из правого нижнего угла таблицы в верхний левый по пути с минимальной суммой
    while (ii > 0 && jj > 0)
    {
        var max = board[ii, jj];
// Очевидно, двигаться мы можем вверх, влево или вверх-влево. Смотрим где наименьший элемент, туда и идем.
        var min = Math.Min(board[ii - 1, jj - 1], Math.Min(board[ii - 1, jj], board[ii, jj - 1]));
        if (min == board[ii - 1, jj - 1])
        {
            if (min != max)
            {
                stack.Push(new CompareStringResult(oldValues[ii - 1], newValues[jj - 1], CompareStringResult.ActionType.Changed));
            }
            else
                stack.Push(new CompareStringResult(newValues[jj - 1], newValues[jj - 1], CompareStringResult.ActionType.NotChanged));
            ii--;
            jj--;
        }
        else if (min == board[ii - 1, jj])
        {
            if (min != max)
                stack.Push(new CompareStringResult(oldValues[ii - 1], null, CompareStringResult.ActionType.Deleted));
            else
                stack.Push(new CompareStringResult(oldValues[ii - 1], newValues[jj], CompareStringResult.ActionType.NotChanged));
            ii--;
        }
        else if (min == board[ii, jj - 1])
        {
            if (min != max)
                stack.Push(new CompareStringResult(null, newValues[jj - 1], CompareStringResult.ActionType.Added));
            else
                stack.Push(new CompareStringResult(oldValues[ii], newValues[jj - 1], CompareStringResult.ActionType.NotChanged));
            jj--;
        }
    }
// Если уперлись в левую стенку, но ещё не дошли до верха
    while (ii > 0)
    {
        var max = board[ii, jj];
        var min = board[ii - 1, jj];
        if (min != max)
            stack.Push(new CompareStringResult(oldValues[ii - 1], null, CompareStringResult.ActionType.Deleted));
        else
            stack.Push(new CompareStringResult(oldValues[ii - 1], newValues[jj], CompareStringResult.ActionType.NotChanged));
        ii--;
    }
// Если уперлись в потолок, но ещё не в левом углу       
    while (jj > 0)
    {
        var max = board[ii, jj];
        var min = board[ii, jj - 1];
        if (min != max)
            stack.Push(new CompareStringResult(null, newValues[jj - 1], CompareStringResult.ActionType.Added));
        else
            stack.Push(new CompareStringResult(oldValues[ii], newValues[jj - 1], CompareStringResult.ActionType.NotChanged));
        jj--;
    }
    return stack;
}

Результат:

  • Черный - нет изменений
  • Синий - изменено
  • Красный - удалено
  • Зеленый - добавлено

Хочу обратить внимание, что сложность алгоритма, как и затраты на память, стали гораздо больше чем в других ответах (N*M), но и качество полученного расстояния выше.

Полный текст примера доступен тут

READ ALSO
Многопоточность. Лучший способ

Многопоточность. Лучший способ

Стоит задача сделать программу мониторинга железок по SNMP(не спрашивайте зачем, сам в шоке) Планирую использовать c# и библиотеку SNMP lexМониториться...

198
Динамические данные с IoC контейнером

Динамические данные с IoC контейнером

Изучаю тему IoC и DIВсё вроде понял зачем как и почему пока не дошел до IoC контейнера Unity

203
Как считать файл из сетевой папки в Xamarin Android(c#)

Как считать файл из сетевой папки в Xamarin Android(c#)

Например, у меня есть txt файл на удалённом компьютере в его открытой сетевой папкеНужно локально считать этот файл

252
Вопрос про парсер CsQuery

Вопрос про парсер CsQuery

Всех приветствую, вопрос такой, изучаю этот парсер, вот страница, которую я хочу разобратьВот мой код

238