Algoritmo per l'unione di più righe di dati

0

Ho bisogno di un algoritmo per unire più righe per i dati, dove una colonna è la colonna dell'indice e se una o più righe hanno lo stesso valore di indice unire i valori della colonna in una singola riga e infine ordinare le righe una nella colonna dell'indice .

Esempio di ASCII ART:

Starting point:

------------------------------------
| IndexCurve | Column A | Column B |
------------------------------------
| 1          | 1        |          |
------------------------------------
| 2          | 5        | 5        |
------------------------------------
| 1          |          | 1        |
------------------------------------
| 2          | 5        | 5        |
------------------------------------
| 3          | 1        |          |
------------------------------------

Outcome:

------------------------------------
| IndexCurve | Column A | Column B |
------------------------------------
| 1          | 1        | 1        |
------------------------------------
| 2          | 5        | 5        |
------------------------------------
| 3          | 1        |          |
------------------------------------

Come puoi vedere le colonne vuote sono state unite, i duplicati sono stati scartati e le righe sono state ordinate nella colonna indice. (NOTA: i valori delle colonne non devono essere aggiunti l'uno all'altro).

Ho cercato di trovare un algoritmo efficace per questo, ma finora credo di aver fallito perché penso che sia piuttosto inefficace e anche che non funzioni correttamente.

Qui ho del codice per mostrarti cosa ho attualmente, i primi pezzi di codice sono solo oggetti POCO per darti un'idea di cosa sto lavorando, ho anche incluso metodi uguali per vedere come confronto gli oggetti .

public interface IWitsmlLogCurveInfo
{
    string Mnemonic { get; set; }
    bool IndexCurve { get; set; }
}

public class WitsmlLogCurveInfo
{
    string Mnemonic { get; set; }
    bool IndexCurve { get; set; }

    protected bool Equals(WitsmlLogCurveInfo other)
    {
        return string.Equals(Mnemonic, other.Mnemonic);
    }

    public override bool Equals(object obj)
    {
        if(ReferenceEquals(null, obj))
        {
            return false;
        }
        if(ReferenceEquals(this, obj))
        {
            return true;
        }
        if(obj.GetType() != this.GetType())
        {
            return false;
        }
        return Equals((WitsmlLogCurveInfo)obj);
    }

    public override int GetHashCode()
    {
        return (Mnemonic != null ? Mnemonic.GetHashCode() : 0);
    }
}

public interface IWitsmlLogDataColumn
{
    IWitsmlLogCurveInfo WitsmlLogCurveInfo { get; set; }
    string Value { get; set; }
}

public class WitsmlLogDataColumn : IWitsmlLogDataColumn
{
    public IWitsmlLogCurveInfo WitsmlLogCurveInfo { get; set; }
    public string Value { get; set; }

    protected bool Equals(WitsmlLogDataColumn other)
    {
        return string.Equals(Value, other.Value) && string.Equals(WitsmlLogCurveInfo, other.WitsmlLogCurveInfo);
    }

    public override bool Equals(object obj)
    {
        if(ReferenceEquals(null, obj))
        {
            return false;
        }
        if(ReferenceEquals(this, obj))
        {
            return true;
        }
        if(obj.GetType() != this.GetType())
        {
            return false;
        }
        return Equals((WitsmlLogDataColumn)obj);
    }

    public override int GetHashCode()
    {
        unchecked
        {
            return ((Value != null ? Value.GetHashCode() : 0) * 397) ^ (WitsmlLogCurveInfo != null ? WitsmlLogCurveInfo.GetHashCode() : 0);
        }
    }
}

public interface IWitsmlLogDataRow
{
    IList<IWitsmlLogDataColumn> Columns { get; set; }
    IWitsmlLogDataColumn GetIndexColumn();
}

public class WitsmlLogDataRow : IWitsmlLogDataRow
{
    public IList<IWitsmlLogDataColumn> Columns { get; set; }

    public IWitsmlLogDataColumn GetIndexColumn()
    {
        return Columns.SingleOrDefault(x => x.WitsmlLogCurveInfo.IndexCurve);
    }

    protected bool Equals(WitsmlLogDataRow other)
    {
        return Columns.All(x => other.Columns.Contains(x));
    }

    public override bool Equals(object obj)
    {
        if(ReferenceEquals(null, obj))
        {
            return false;
        }
        if(ReferenceEquals(this, obj))
        {
            return true;
        }
        if(obj.GetType() != this.GetType())
        {
            return false;
        }
        return Equals((WitsmlLogDataRow)obj);
    }

    public override int GetHashCode()
    {
        return (Columns != null ? Columns.GetHashCode() : 0);
    }
}

public enum FrictionType
{
    Annulus,
    Sliding,
    Rotating
}

public interface IWitsmlLogFriction 
{
    FrictionType Type { get; set; }
    IList<IWitsmlLogDataRow> Rows { get; set; }
}

public class WitsmlLogFriction : IWitsmlLogFriction
{
    public FrictionType Type { get; set; }
    public IList<IWitsmlLogDataRow> Rows { get; set; }

    public override string ToString()
    {
        return string.Format("FrictionType: {0}", Type);
    }

    protected bool Equals(WitsmlLogFriction other)
    {
        return Type == other.Type && Rows.All(x => other.Rows.Contains(x));
    }

    public override bool Equals(object obj)
    {
        if(ReferenceEquals(null, obj))
        {
            return false;
        }
        if(ReferenceEquals(this, obj))
        {
            return true;
        }
        if(obj.GetType() != this.GetType())
        {
            return false;
        }
        return Equals((WitsmlLogFriction)obj);
    }

    public override int GetHashCode()
    {
        unchecked
        {
            return ((int)Type * 397) ^ (Rows != null ? Rows.GetHashCode() : 0);
        }
    }
}

Ecco la Funzione Algoritmo stessa:

private IList<IWitsmlLogDataRow> CombineMultipleFrictionTypes(IList<WitsmlLogFriction> witsmlLogFrictions, WitsmlLogCurveInfo indexCurve)
{
    if(indexCurve == null)
    {
        throw new NoNullAllowedException("IndexCurve can not be null!");
    }
    if(witsmlLogFrictions.Count == 1)
    {
        return witsmlLogFrictions.First().Rows;
    }
    WitsmlLogFriction witsmlLogFrictionA = witsmlLogFrictions.FirstOrDefault();
    List<IWitsmlLogDataRow> rows = new List<IWitsmlLogDataRow>();
    if (witsmlLogFrictionA == null)
    {
        return rows;
    }
    foreach(WitsmlLogFriction witsmlLogFrictionB in witsmlLogFrictions.Where(witsmlLogFriction => witsmlLogFriction.Type != witsmlLogFrictionA.Type))
    {
        foreach (IWitsmlLogDataRow witsmlLogDataRowA in witsmlLogFrictionA.Rows)
        {
            // Get index curve for row A
            IWitsmlLogDataColumn indexCurveA = witsmlLogDataRowA.GetIndexColumn();
            if (indexCurveA == null) continue;



            IWitsmlLogDataRow tempWitsmlLogDataRowA = new WitsmlLogDataRow(witsmlLogDataRowA.Columns);
            foreach(IWitsmlLogDataRow witsmlLogDataRowB in witsmlLogFrictionB.Rows)
            {
                // Get index curve for row B
                IWitsmlLogDataColumn indexCurveB = witsmlLogDataRowB.GetIndexColumn();
                if (indexCurveB == null) continue;



                // Compare index curve values
                if(indexCurveA.Equals(indexCurveB))
                {
                    // Index curve values are identical, append columns from row B onto row A, except row B's index column
                    foreach(IWitsmlLogDataColumn column in witsmlLogDataRowB.Columns.Where(column => !column.WitsmlLogCurveInfo.Equals(indexCurve)))
                    {
                        tempWitsmlLogDataRowA.Columns.Add(column);
                    }
                }
                else
                {
                    rows.Add(witsmlLogDataRowB);
                }
            }
            // Add the new row
            rows.Add(tempWitsmlLogDataRowA);
        }
    }
    switch(indexCurve.IndexType)
    {
        case LogIndexType.datetime:
            return rows.OrderBy(x => Convert.ToDateTime(x.GetIndexColumn().Value)).ToList();
        default:
            throw new ArgumentOutOfRangeException("indexCurve", "IndexType: " + indexCurve.IndexType + " is not supported.");
    }
}

Il problema è che penso che sia piuttosto inefficace, ma potrebbe anche essere l'unico modo per farlo, e aggiunge più dati che dovrebbe. Quale sarebbe un modo migliore ed efficace per risolvere questo?

    
posta furier 28.01.2015 - 11:59
fonte

2 risposte

3
  1. Ordina la tua tabella per indice
  2. univoca banalmente tutti i dati con lo stesso indice (dato che saranno tutti insieme), quando l'indice cambia al valore successivo, scrivi la riga e ripeti.

Potresti subire un colpo sull'ordinamento, ma generalmente è un'operazione comune con molti buoni algoritmi esistenti in grado di ordinare in modo efficiente il tuo set di dati. Dopodiché, manipolare il set di dati ordinato è facile.

    
risposta data 28.01.2015 - 13:02
fonte
1

Poiché è necessario ordinare i valori nell'indice, selezionerei SortedDictionary e manterrò la logica di fusione all'interno dell'oggetto Row,

public class Row
{
    public int Index { get; set; }
    public string IndexA { get; set; }
    public string IndexB { get; set; }

    public void Merge (Row other}
    {
        if (Index != other.Index}
            throw new Exception("Cannot merge");

        If (string.isNullOrEmpty(IndexA))
            IndexA = other.IndexA;

        //any other merge logic
    }
}

Questo codice può essere utilizzato per scorrere le righe e unirle,

IList<Row> MergeAndSort(IList<Row> rows)
{
   var dic = new SortedDictionary<int,Row>();    
   foreach(Row row in rows)
   {
       if (dic[row.Index] == null)
           dic[row.Index] = row;
       else
           dic[row.Index].Merge(row); 
   }
   return dic.SelectMany (d => d.Value).ToList();
}
    
risposta data 01.02.2015 - 05:44
fonte

Leggi altre domande sui tag