1

This is related to a previous question, but it seems different enough to post it separately:

I have settings that are stored in string arrays from user input (DomAttributeIds and IntlAttributeIds). I am trying to conditionally build an array of values to execute some code on. Conditions are:

  1. If DomAttributesSettings exist, create an array of the values and pass them to the AddAttributeEdit() method.
  2. If IntlAttributesSettings exist, create an array of those settings and combine them with the settings from condition one distinctly (no duplicates) and pass that array to the rest of the code, and ultimately each array element to the AddAttributeEdit() method.

The code below seems to work except for the "no duplicates" part. I thought using Linq's Union and/or Distinct methods would do this, but I must be doing something wrong. My code throws the following exception:

Multiple controls with the same ID 'trAttribute_493' were found. FindControl requires that controls have unique IDs.

I know that this is because that id exists in both settings. The AddAttributeEdit() method at the end contains code that builds a table and cells with Ids based on the values passed to it. What am I doing wrong to get a distinct union of the two arrays?

Here is the code:

    private void LoadAttributes()
    {
        if (!string.IsNullOrEmpty(DomAttributesSetting))
        {
            string[] attributeIds;
            if (!string.IsNullOrEmpty(IntlAttributesSetting))
            {

                string[] domattributeIds = DomAttributesSetting.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                string[] intlattributeIds = IntlAttributesSetting.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                IEnumerable<string> atrributeIdList = domattributeIds.Union(intlattributeIds).Distinct();
                attributeIds = atrributeIdList.ToArray();
            }
            else
            {
                attributeIds = DomAttributesSetting.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            } 
            foreach (string attributeId in attributeIds)
            {
                int attrId = -1;
                if (int.TryParse(attributeId, out attrId) && attrId != -1)
                {
                    Arena.Core.Attribute attribute = new Arena.Core.Attribute(attrId);
                    PersonAttribute personAttribute = (PersonAttribute)person.Attributes.FindByID(attribute.AttributeId);
                    if (personAttribute == null)
                        personAttribute = new PersonAttribute(person.PersonID, attrId);

                    AddAttributeEdit(attribute, personAttribute, true);
                }

            }


        }

    }...
5
  • 3
    Can I get a couple paragraphs? Commented May 9, 2012 at 14:49
  • @Austin Not sure what you mean. Commented May 9, 2012 at 14:55
  • If you can see the proposed edits, you will know I what I mean. Commented May 9, 2012 at 15:02
  • 1
    I think what Austin means is that your explanation at the top is a bit of an eyebender and could be split into paragraphs to make it more readable. Commented May 9, 2012 at 15:04
  • Gotcha, not sure what happend there. It looked fine in the edit mode, but came out "squishy". Thanks to zimdanen for fixing it :) Commented May 9, 2012 at 16:24

6 Answers 6

2

You probably have padding around the values in the comma delimited lists (e.g "Prop1, Prop2" vs "Prop1,Prop2") or the casing is different.

Try trimming each value from the input and using a case-insensitive comparer like this:

var domattributeIds = DomAttributesSetting
    .Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
    .Select(x=>x.Trim());

var intlattributeIds = IntlAttributesSetting
    .Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
    .Select(x=>x.Trim());

var attributeIds = domattributeIds
    .Union(intlattributeIds, StringComparer.InvariantCultureIgnoreCase)
    .ToArray();

You shouldn't even need to call Distinct() at the end.

Sign up to request clarification or add additional context in comments.

1 Comment

The answer ended up being an error on my compiling rather than the actual code. I went ahead and marked this as the answer, though, as it got me to explore the use of 'var' which I had not used yet. I also like the technique of cleaning up the string and using ints to make it more robust.
1

You must have different string representations of some ints - for example leading "0"s.

Your best bet is to convert to ints first, then run Distinct.

Something like:

var ints = attributeIds.Select( s =>
{
  int i;
  return Int32.TryParse( s, out i ) ? i : -1;
};

var uniques = ints.Where( i => i != -1 ).Distinct().ToList();

foreach ( int attrId in uniques )
{
  Arena.Core.Attribute attribute = ...

Comments

1

Do you have two strings that vary only by case? Linq won't see those as duplicates by default. Try this instead:

domattributeIds.Union(intlattributeIds, StringComparer.CurrentCultureIgnoreCase)

2 Comments

that is a cool thought. In this case, however, I am using the exact same class on the exact same SQL data pool, so the arrays are being generated with the same format.
Without seeing the original strings, I'm out of ideas. Can you add them to your question?
1

The following code will return the distinct string array from 2 string arrays

public string[] UniqueNames(string[] names1, string[] names2) {
    newName = names1.ToList();
    foreach (var dr in names2) {
        if (!newName.Contains(dr)) {
            newName.Add(dr);
        }
    }
    string[] newNameArray = newName.ToArray();
    return newNameArray;
}

or you can also try,

public string[] UniqueNames(string[] names1, string[] names2) {            
    return names1.Union(names2).ToArray(); ;            
}

Comments

0
 string a = "a,b, c";
 string b = "b,c,d";
 String[] ass  = a.Split( new char[]{','}, StringSplitOptions.RemoveEmptyEntries);
 String[] bss =  b.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
 var list = ass.Union(bss).Distinct().ToArray();
 StringBuilder sb = new StringBuilder();
 foreach ( String s in list)
  {
    sb.Append(s);
  }
 Text = sb.ToString();

The final text is "ab ccd" because of the space. make sure your inputs dont contain spaces

2 Comments

can you not use .Trim() to remove the whitespace.
ofcourse I can.. I was just giving an example where apparently similiar stings can pass through the distinct() and union() calls
0

Use Union from LINQ, for example:

string[] domattributeIds = new string[] { "a", "b", "c" };
string[] intlattributeIds = new string[] { "a", "c", "d" };

string[] combined = domattributeIds.Union(intlattributeIds).ToArray();

the new array "combined" has values "a", "b", "c", "d"

2 Comments

Thanks for the quick response. How is that different from what I am already doing in the first if section, aside from the fact that you combined them into a single call, where I broke it into a few pieces?
I did the same thing and got the exact result.. gmaness are you sure there are no additional white spaces in your strings? could you please print the strings out for us?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.