tags:

views:

92

answers:

3
public class InvestorMailing
{
    public string To { get; set; }

    public IEnumerable<string> Attachments { get; set; }

    public int AttachmentCount { get; set; }

    public long AttachmentSize { get; set; }
}

i have an IList<InvestorMailing> mailingList. if the attachment size is greater than x, then i need to split my object into chunks. is there an easy linq-y way to do this?

Edited:

this is how i'm generating my mailings:

        var groupedMailings = mailingList.GroupBy(g => g.GroupBy);

        var investorMailings = groupedMailings.Select(
            g => new DistinctInvestorMailing
            {
                Id = g.Select(x => x.Id).FirstOrDefault(),
                To = g.Key.Trim(),
                From = g.Select(x => x.From).FirstOrDefault(),
                FromName = g.Select(x => x.FromName).FirstOrDefault(),
                Bcc = g.Select(x => x.Bcc).FirstOrDefault(),
                DeliveryCode = g.Select(x => x.DeliveryCode).FirstOrDefault(),
                Subject = g.Select(x => x.Subject).FirstOrDefault(),
                Body = g.Select(x => x.Body).FirstOrDefault(),
                CommentsOnStatus = g.Select(x => x.CommentsOnStatus).FirstOrDefault(),
                Attachments = g.Select(x => x.AttachmentPath),
                AttachmentCount = g.Select(x => x.AttachmentPath).Count(),
                AttachmentSize = g.Sum(x => x.AttachmentSize),
                MailType = g.Select(x => x.MessageType).FirstOrDefault()
            }
        ).ToList();
+1  A: 

It should be pretty simple to do it with a standard method. Consider this example:

class Foo
{
    public Foo(int weight) { Weight = weight; }
    public int Weight { get; set; }
}

...

IEnumerable<IList<Foo>> GroupFoosByWeight(IList<Foo> foos, int weightLimit)
{
    List<Foo> list = new List<Foo>();
    int sumOfWeight = 0;

    foreach (Foo foo in foos)
    {
        if (sumOfWeight + foo.Weight > weightLimit)
        {
            yield return list;
            sumOfWeight = 0;
            list.Clear();
        }

        list.Add(foo);
        sumOfWeight += foo.Weight;
    }

    if (list.Count > 0)
        yield return list;
}

...

List<Foo> foos = new List<Foo>()
{
    new Foo(15), new Foo(32), new Foo(14), new Foo(19), new Foo(27)
};

foreach (IList<Foo> list in GroupFoosByWeight(foos, 35))
{
    Console.WriteLine("{0}\t{1}", list.Count, list.Sum(f => f.Weight));
}

Edit

I worked on it a bit and produced a LINQ version. It doesn't really save much code in this case, but it's a start.

int weightLimit = 35;
int fooGroup = 0;
int totalWeight = 0;

Func<Foo, int> groupIncrementer = f =>
{
    if (totalWeight + f.Weight > weightLimit)
    {
        fooGroup++;
        totalWeight = 0;
    }

    totalWeight += f.Weight;

    return fooGroup;
};

var query = from foo in foos
            group foo by new { Group = groupIncrementer(foo) }
                into g
                select g.AsEnumerable();

foreach (IList<Foo> list in query)
{
    Console.WriteLine("{0}\t{1}", list.Count, list.Sum(f => f.Weight));
}
Anthony Pegram
this worked -- thanks
CurlyFro
A: 

Hey,

Yes:

var highs = mailingList.Where(i => i.AttachmentSize > 10000).ToList();
var lows = mailingList.Where(i => i.AttachmentSize <= 10000).ToList();

How do you need to break them apart aside from this?

HTH.

Brian
I *think* he wants to process these things in batches. So once he exceeds some given threshold, perform an action and continue. So it's not really the individual size, but the collective.
Anthony Pegram
+1  A: 

Here's a way to do it using some LINQ to find a chunk that has enough space left to add the attachment:

var chunks = new List<List<InvestorMailing>>();
int maxAttachmentsSize = 10;

foreach (InvestorMailing mail in mailingList)
{
    var chunkWithSpace = chunks
        .Where(list => list.Sum(x => x.AttachmentSize) +
                       mail.AttachmentSize <= maxAttachmentsSize)
        .FirstOrDefault();

    if (chunkWithSpace != null)
    {
        chunkWithSpace.Add(mail);
    } else {
        chunks.Add(new List<InvestorMailing> { mail });
    }
}

The result is stored in chunks.

Mark Byers