Tell me more ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

The following code is pretty ugly. I suspect that there is a more functional and elegant way of achieving this result.

var lines = 
new[]{ 
    new{Head="A",Value="1"},
    new{Head="",Value="2"},
    new{Head="",Value="3"},
    new{Head="",Value="4"},
    new{Head="B",Value="5"},
    new{Head="B",Value="6"},
    new{Head="C",Value="7"},
    new{Head="",Value="8"},
    new{Head="D",Value="9"},
    new{Head="",Value="10"}};

string currentHead="";
string currentValue="";

lines.Select(line=>{
        string newHead;
        string newValue;
        if (String.IsNullOrEmpty(line.Head))
        {
            newHead = currentHead;
        } else
        {
            newHead = line.Head;
            currentHead = line.Head;
        }
        if (String.IsNullOrEmpty(line.Value))
        {
            newValue = currentValue;
        } else
        {
            newValue = line.Value;
            currentValue = line.Value;
        }
        return new{Head=newHead,Value=newValue};}).ToList();

The desired output is to produce

A,1

A,2

A,3

A,4

B,5

B,6

C,7

C,8

D,9

D,10

share|improve this question
2  
I don't see a hierarchical list here — I see a bunch of empty keys (and your code depends on the ordering of the array). Do you have any control over the creation of the array, and can you show the code for that? Or is this really how the array is filled? – codesparkle Aug 14 '12 at 12:03
Yup, it is deterministically ordered. It is directly transformed from an excel sheet. The excel list is grouped and I need to "pad" the empty entries with the last value on that column. Granted that the list type is not hierarchical, but the data is grouped. – Tormod Aug 14 '12 at 12:07
Do you need that Values there? Can't you compute them? They seem to be 1,2,3,…,10. – svick Aug 14 '12 at 12:29
The live data are not like that. I just created test data in sequence so that it would be easier to see errors in the algorithm. Otherwise, sure, I would use the overload of Select() that provides a running counter. – Tormod Aug 14 '12 at 12:33

2 Answers

up vote 2 down vote accepted

You need to look through your code with an analytical eye and discover the pattern that you are implementing. I call it default if (null or) empty.

So I created an extension method to implement that pattern.

public static string DefaultIfEmpty(this string source, string defaultValue)
{
    return string.IsNullOrEmpty(source) ? defaultValue : source;
}

(Note of caution: you may want to choose a different name for it since this method already exists in LINQ; technically, this is an overload, which could create problems if a future version of C# adds this signature.)

This makes it possible to adapt the LINQ expression:

var currentHead = string.Empty;
var currentValue = string.Empty;
var result = lines.Select(
    line =>
    {
        currentHead = line.Head.DefaultIfEmpty(currentHead);
        currentValue = line.Value.DefaultIfEmpty(currentValue);
        return new { Head = currentHead, Value = currentValue };
    }).ToList();

Sweet, isn't it?

share|improve this answer

Another options would be to use Aggregate():

var result = lines.Aggregate(
    seed: lines.Take(0).ToList(), // get an empty list of the anonymous type
    func: (list, line) => {
        list.Add(new {
            // you can implement a fast Last() method for lists or use list[list.Count - 1] if list is long/you're worried about efficiency
            Head = string.IsNullOrEmpty(line.Head) ? list.Last().Head : line.Head,
            Value = string.IsNullOrEmpty(line.Value) ? list.Last().Value : line.Value
        });
        return list;
    }
);
share|improve this answer
Very nice trick in generating an empty list of an anonymous type (the seed). More efficient with captured variable in the object initializer: "Head = (String.IsNullOrEmpty(line.Head))?currentHead : (currentHead=line.Head)," – Tormod Sep 3 '12 at 12:51

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.