0

I got a list of strings,on which I would like to do an operation which concats each item with rest of the items. The below test fails at the moment, I think the join is not the correct linq method I should be using- can you please let me know how to get this done? The pattern of the output should tell how the projection should be,if not the rule is simple:take one item and concatenate with all the other items and then move to the next item.Test below:

[Test]
        public void Should_concatenate_all_items()
        {
            var items = new List<string> {"a", "b", "c", "d"};

            var concatenatedList = items .Join(items , x => x, y => y, (x, y) => string.Concat(x, y));

            foreach (var item in concatenatedList)
            {                
                //Should output:ab
                //Should output:ac
                //Should output:ad
                //Should output:bc
                //Should output:bd
                //Should output:cd
                Console.WriteLine(item);
            }
        }   

Note: I'm using .NET 3.5.

Mike
  • 3,204
  • 8
  • 47
  • 74
  • What is `potentialItems` and it's elements? Is that the full output or a sample? – Cyral Oct 15 '13 at 23:17
  • Okay, thats what I thought – Cyral Oct 15 '13 at 23:22
  • Why use Linq for something like this? It's just a nested loop, it would be done already, and in a couple of months time, what it was doing would be extremely obvious. Idea behind Linq was greater power of expression, not express everything in it no matter what... – Tony Hopkinson Oct 15 '13 at 23:41

3 Answers3

3

You could use something like this:

var concatenatedList =
    from x in items.Select((str, idx) => new { str, idx })
    from y in items.Skip(x.idx + 1)
    select x.str + y;

Or in fluent syntax:

var concatenatedList =
    items.Select((str, idx) => new { str, idx })
         .SelectMany(x => items.Skip(x.idx + 1), (x, y) => x.str + y);
p.s.w.g
  • 146,324
  • 30
  • 291
  • 331
  • 1
    +1. Following question have more samples of [cross join](http://stackoverflow.com/questions/56547/how-do-you-perform-a-cross-join-with-linq-to-sql) used here. – Alexei Levenkov Oct 15 '13 at 23:28
0
var concatenatedList = (from i in items
                     from x in items
                     where i != x
                     select string.Concat(i, x)).ToList();

For the exact output that you listed:

 var concatenatedList = (from i in items
                     from x in items
                     where i != x && items.IndexOf(i) < items.IndexOf(x)
                     select string.Concat(i, x)).ToList();
AD.Net
  • 13,352
  • 2
  • 28
  • 47
0

I think my solution may be overkill, but in real world situations it is probably more helpful. Also, I could not find a clean way to do it in Linq. Linq's Except does not seem suited for this.

You can use an IEnumerator to enumerate the values for you.

public class ConcatEnum : IEnumerator
{
    public List<String> _values;

    // Enumerators are positioned before the first element 
    // until the first MoveNext() call. 
    int position1 = 0;
    int position2 = 0;

    public ConcatEnum(List<String> list)
    {
        _values = list;
    }

    public bool MoveNext()
    {
        position2 = Math.Max(position2 + 1, position1 + 1);
        if (position2 > _values.Count - 1){
            position1++;
            position2 = position1 + 1;
        }

        return position1 < _values.Count - 1;
    }

    public void Reset()
    {
        position1 = 0;
        position2 = 0;
    }

    object IEnumerator.Current
    {
        get
        {
            return Current;
        }
    }

    public String Current
    {
        get
        {
            try
            {
                return _values[position1] + _values[position2];
            }
            catch (IndexOutOfRangeException)
            {
                throw new InvalidOperationException();
            }
        }
    }

    public IEnumerator GetEnumerator()
    {
        this.Reset();
        while (this.MoveNext())
        {
            yield return Current;
        }
    }
}

Call it like this:

var items = new List<string> { "a", "b", "c", "d" };
foreach (var i in new ConcatEnum(items))
{
    //use values here
}
Millie Smith
  • 4,536
  • 2
  • 24
  • 60