Sorting Clothing Sizes (XXS XS S M L XL XXL)

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • DarrenW
    New Member
    • Mar 2007
    • 5

    Sorting Clothing Sizes (XXS XS S M L XL XXL)

    I've been trying to find a reasonable way to sort a collection of clothing items by size but google isn't helping my out very much. I know this has to have been done before. I've seen an example written in Python but I don't do Python and the syntax is far too abstract to even sit and try to pick it apart.

    The best thing I've been able to come up with is to:
    1. Reverse the strings
    2. Sort them reversed
    3. Reverse the order
    4. Reverse the strings

    example set: S XL M XXS L XXL

    // Reverse the strings
    1. S LX M SXX L LXX

    // Sort them reversed
    2. L LX LXX M S SX SXX

    // Reverse the order
    3. SXX SX S M L LX LXX

    // Reverse the strings
    4. XXS XS S M L XL XXL

    Can anyone come up with something faster/better?
  • RedSon
    Recognized Expert Expert
    • Jan 2007
    • 4980

    #2
    You are only looking at 7 things why don't you just sort them by hard coding the values? Or even assign numbers to them as a key value pair and sort that way.

    Comment

    • DarrenW
      New Member
      • Mar 2007
      • 5

      #3
      Originally posted by RedSon
      You are only looking at 7 things why don't you just sort them by hard coding the values? Or even assign numbers to them as a key value pair and sort that way.
      That was just an example. In the production environment the sorting routine needs to be able to sort based on text alone. There is no indication that those will be the only values and also no rule that states the sizes will all ways appear as XS, XXS, or XL. For example, the size may come in as X-S or XSM.

      Whatever the scheme, it will continue to be followed throughout the set of item sizes.

      I'd like to be able to also accomodate schemes like X-SMALL or XX-SMALL as I've seen that scheme in some of the older data, but there is no guarantee that a future data set won't have that scheme or any other common clothing size scheme.

      There are also situations where there my be a color or other descriptor following the size such as XL (Black). For those situations I currently split the string between the size and descriptor and process them separately which makes sense to me.

      Comment

      • RedSon
        Recognized Expert Expert
        • Jan 2007
        • 4980

        #4
        Originally posted by DarrenW
        That was just an example. In the production environment the sorting routine needs to be able to sort based on text alone. There is no indication that those will be the only values and also no rule that states the sizes will all ways appear as XS, XXS, or XL. For example, the size may come in as X-S or XSM.

        Whatever the scheme, it will continue to be followed throughout the set of item sizes.

        I'd like to be able to also accomodate schemes like X-SMALL or XX-SMALL as I've seen that scheme in some of the older data, but there is no guarantee that a future data set won't have that scheme or any other common clothing size scheme.

        There are also situations where there my be a color or other descriptor following the size such as XL (Black). For those situations I currently split the string between the size and descriptor and process them separately which makes sense to me.
        It's impossible to do this based on a text sort alone. You must have a set amount of tokens or at least a predetermined set of data. Making your tokens S M L is fine then you can parse the XS XXXXXXS and XXXXXXXXXXXS easy enough with out creating more cases to sort by, just convert the X's to a number. But sorting S X-Small XSML XBSML SMLXB DUCK CAR BOAT will never work.

        Comment

        • DarrenW
          New Member
          • Mar 2007
          • 5

          #5
          Originally posted by DarrenW

          Whatever the scheme, it will continue to be followed throughout the set of item sizes.
          Let me spell out this statement...

          Originally posted by DarrenW
          ... set of item sizes.
          - The set of strings received will all correlate to clothing sizes; there will be no BOATs, DUCKs, BOMBs, or MAZDAs.

          Originally posted by DarrenW
          Whatever the scheme, it will continue to be followed throughout...
          - If, in this set of strings, the size SMALL is indicated as SM, then all other sizes relating to small will also use SM; XXSM XSM SM. The set will not be mixed; there will be no XX-SMALL XS SM.

          For the record... The method I first described doesn't work because the result set will have the large items reversed.

          At any rate, I believe I may have come up with a workable solution. I'll post it if it works.

          Comment

          • RedSon
            Recognized Expert Expert
            • Jan 2007
            • 4980

            #6
            Originally posted by DarrenW
            I'd like to be able to also accomodate schemes like X-SMALL or XX-SMALL as I've seen that scheme in some of the older data, but there is no guarantee that a future data set won't have that scheme or any other common clothing size scheme.
            This reads to me like you are mixing entries for different representations of extra small shirt. Your first post talks about XXS XS S M L then in subsequent posts you talk about X-SMALL, XSM and what not. So sorry for the confusion.

            What you need to do, and I suspect you are already doing this is identify what three tokens you are going to identify as small, medium and large. SM, MED, and LG work fine for this. Your next step is to count the number of Xs that come before these tokens. This should be fairly simple to sort, convert number of Xs to an int and sort from largest to smallest since more Xs means smaller or larger dpeneding on size token. Then after you have this logic, you can add in the "ignore everything else" logic. That means that XXX-SMALL will be treated the same as XXX-=--=sdlfjsdsdkjoiv nSMsdfiojg. Then after you have that you want to add the logic in that either removes all the junk characters or tells the user to "get a life" and stop entering in bogus data to try to muck up the system.

            Comment

            • DarrenW
              New Member
              • Mar 2007
              • 5

              #7
              For those interested (and also those who like to find bugs)... The following is the quick and dirty solution I came up with yesterday that meets all of the needs I specified. The code is NOT fail safe and NOT checked for exceptions. It should NOT be used in a production environment, especially when the input data and size rules will not be reasonably constant. It could be heavily optimized but that should be unnecessary. Thanks RedSon, the discussion with you helped to get my mind going in the right direction.


              ClothingSizeSor ter.cs
              Code:
              namespace Clothing_Size_Sorter
              {
              	using System;
              	using System.Collections.Generic;
              	using System.Collections;
              	using System.Text;
              
              	public class ClothingSizeKey
              	{
              		public string[] adverbs;
              		public string delimiter;
              		public string size;
              		public int value;
              	}
              
              	public class ClothingSizeSorter
              	{
              		public string[] small_keys;
              		public string[] medium_keys;
              		public string[] large_keys;
              		public string[] adverbs;
              		public string adverb_delimiters;
              
              		public ClothingSizeSorter(string small_keys, string medium_keys, string large_keys, string adverbs, string adverb_delimiters, char key_delimiter)
              		{
              			this.small_keys = small_keys.Split(key_delimiter);
              			this.medium_keys = medium_keys.Split(key_delimiter);
              			this.large_keys = large_keys.Split(key_delimiter);
              			this.adverbs = adverbs.Split(key_delimiter);
              			this.adverb_delimiters = adverb_delimiters;
              		}
              
              		public int CompareSizeKeysByValue(ClothingSizeKey x, ClothingSizeKey y)
              		{
              			if (x == null)
              			{
              				if (y == null)
              				{
              					// If x is null and y is null, they're
              					// equal. 
              					return 0;
              				}
              				else
              				{
              					// If x is null and y is not null, y
              					// is greater. 
              					return -1;
              				}
              			}
              			else
              			{
              				// If x is not null...
              				//
              				if (y == null)
              				// ...and y is null, x is greater.
              				{
              					return 1;
              				}
              				else
              				{
              					int retval = x.value.CompareTo(y.value);
              
              					if (retval != 0)
              					{
              						return retval;
              					}
              					else
              					{
              						if (x.value < 0)
              						{
              
              							return Array.IndexOf<string>(small_keys, x.size).CompareTo(Array.IndexOf<string>(small_keys, y.size));
              						}
              						else if (x.value > 0)
              						{
              							return Array.IndexOf<string>(large_keys, x.size).CompareTo(Array.IndexOf<string>(large_keys, y.size));
              						}
              						else
              						{
              							return Array.IndexOf<string>(medium_keys, x.size).CompareTo(Array.IndexOf<string>(medium_keys, y.size));
              						}
              					}
              				}
              			}
              		}
              
              		public void Sort(string sizes, out string output, char delimiter)
              		{
              			string[] out_str;
              			Sort(sizes.Split(delimiter), out out_str);
              
              			output = "";
              			for (int i = 0; i < out_str.Length; i++)
              			{
              				output += out_str[i];
              				if (i + 1 < out_str.Length)
              					output += delimiter;
              			}
              		}
              
              		public void Sort(string[] sizes, out string[] output)
              		{
              			int i, x;
              			List<ClothingSizeKey> size_keys = new List<ClothingSizeKey>();
              			ClothingSizeKey size_key;
              			string[] size_key_parts;
              			string key_adverbs;
              			List<string> sorted_sizes = new List<string>();
              			string size_str;
              			int last_adverb_delimiter;
              
              			if (sizes.Length < 2)
              			{
              				output = sizes;
              				return;
              			}
              
              			// interpret each size key in sizes and store it in size_keys
              			for (i = 0; i < sizes.Length; i++)
              			{
              				size_key = new ClothingSizeKey();
              				size_key.adverbs = new string[0];
              				key_adverbs = "";
              
              				// extract the key parts
              				if ((adverb_delimiters != null) && (adverb_delimiters.Length > 0))
              				{
              					// split by delimiter (get last index)
              					last_adverb_delimiter = sizes[i].LastIndexOfAny(adverb_delimiters.ToCharArray());
              					
              					if (last_adverb_delimiter >= 0)
              					{
              						key_adverbs = sizes[i].Substring(0, last_adverb_delimiter);
              						size_key.size = sizes[i].Substring(last_adverb_delimiter + 1);
              						size_key.delimiter = sizes[i][last_adverb_delimiter].ToString();
              					}
              					else
              					{
              						// no delimiters so split by adverb
              						size_key.delimiter = "";
              					}
              				}
              
              				if (size_key.delimiter.Length == 0)
              				{
              					size_key_parts = sizes[i].Split(adverbs, StringSplitOptions.RemoveEmptyEntries);
              
              					size_key.size = size_key_parts[0];
              					key_adverbs = sizes[i].Replace(size_key.size, "");
              					size_key.delimiter = "";
              				}
              
              				// separate repeating adverbs
              				
              				x = 0;
              				while (x < key_adverbs.Length)
              				{
              					foreach (string adverb in adverbs)
              					{
              						if (key_adverbs.Substring(x).StartsWith(adverb))
              						{
              							Array.Resize<string>(ref size_key.adverbs, size_key.adverbs.Length + 1);
              							size_key.adverbs[size_key.adverbs.Length - 1] = adverb;
              							x += adverb.Length;
              
              							//if ((x < key_adverbs.Length) && (size_key.delimiter.IndexOf(key_adverbs[x]) >= 0))
              							if ((x < key_adverbs.Length) && (adverb_delimiters.IndexOf(key_adverbs[x]) >= 0))
              							{
              								size_key.adverbs[size_key.adverbs.Length - 1] += key_adverbs[x].ToString();
              								x++;
              							}
              						}
              					}
              					if (x == 0)
              					{
              						// Bad delimiter
              						output = null;
              						return;
              					}
              				}
              
              				size_keys.Add(size_key);
              			}
              
              			// assign size key values
              			for (i = 0; i < size_keys.Count; i++)
              			{
              				if (Array.IndexOf<string>(small_keys, size_keys[i].size) >= 0)
              				{
              					x = -10;
              				}
              				else if (Array.IndexOf<string>(large_keys, size_keys[i].size) >= 0)
              				{
              					x = 10;
              				}
              				else
              				{
              					x = 0;
              				}
              
              				size_keys[i].value = x + (x * size_keys[i].adverbs.Length);
              			}
              
              			// sort
              			size_keys.Sort(CompareSizeKeysByValue);
              			
              			// build sorted values array
              			for (i = 0; i < size_keys.Count; i++)
              			{
              				size_str = "";
              				if (size_keys[i].adverbs.Length > 0)
              				{
              					for (x = 0; x < size_keys[i].adverbs.Length; x++)
              					{
              						size_str += size_keys[i].adverbs[x];
              					}
              				}
              				if (size_keys[i].delimiter.Length > 0)
              				{
              					size_str += size_keys[i].delimiter;
              				}
              				size_str += size_keys[i].size;
              
              				sorted_sizes.Add(size_str);
              			}
              
              			output = sorted_sizes.ToArray();
              		}
              	}
              }
              Program.cs
              Code:
              using System;
              using System.Collections.Generic;
              using System.Collections;
              using System.Text;
              using Clothing_Size_Sorter;
              
              namespace ClothingSort
              {
              	class Program
              	{
              		static void Main(string[] args)
              		{
              			string spaced_input_sizes;
              			string dotted_input_sizes;
              			string sorted_sizes;
              			string[] input_sizes_array;
              			string[] sorted_sizes_array;
              
              			// Space Delimited Sizes
              			//spaced_input_sizes = "XS S XL M XXS L XXL";
              			spaced_input_sizes = "X-S S X-L M XX-S L XX-L";
              			//spaced_input_sizes = "EXTRA-SMALL SMALL EXTRA-LARGE MEDIUM EXTRAEXTRA-SMALL LARGE EXTRAEXTRA-LARGE";
              			//spaced_input_sizes = "EXTRA-SMALL SMALL EXTRA-LARGE MEDIUM EXTRA-EXTRA-SMALL LARGE EXTRA-EXTRA-LARGE";
              			//spaced_input_sizes = "EXTRA-SMALL SMALL EXTRA-LARGE MEDIUM EXTRA*EXTRA-SMALL LARGE EXTRA*EXTRA-LARGE";
              			
              			// Dot Delimited Sizes
              			dotted_input_sizes = "EX SMALL.SMALL.EX LARGE.MEDIUM.EX EX SMALL.LARGE.EX EX LARGE";
              
              			// Arrayed Sizes
              			input_sizes_array = new string[] { "SUPER SMALL", "SMALL", "SUPER LARGE", "MEDIUM", "SUPER SUPER SMALL", "SUPER SUPER LARGE" };
              
              			ClothingSizeSorter css;
              			css = new ClothingSizeSorter("S SM SMALL", "M MED MEDIUM", "L LRG LARGE", "X EX EXTRA SUPER", "-* ", ' ');
              
              			// Space Delimited Sizes
              			css.Sort(spaced_input_sizes, out sorted_sizes, ' ');
              			Console.WriteLine("Space Delimited");
              			Console.WriteLine("Input: " + spaced_input_sizes);
              			Console.WriteLine("Output: " + sorted_sizes);
              			Console.WriteLine();
              
              			// Dot Delimited Sizes
              			css.Sort(dotted_input_sizes, out sorted_sizes, '.');
              			Console.WriteLine("Dot Delimited");
              			Console.WriteLine("Input: " + dotted_input_sizes);
              			Console.WriteLine("Output: " + sorted_sizes);
              			Console.WriteLine();
              
              			// Array Sizes
              			css.Sort(input_sizes_array, out sorted_sizes_array);
              			Console.WriteLine("Arrayed");
              			Console.WriteLine("Input:");
              			for (int i = 0; i < input_sizes_array.Length; i++)
              			{
              				Console.WriteLine(input_sizes_array[i]);
              			}
              			Console.WriteLine("Output:");
              
              			for (int i = 0; i < sorted_sizes_array.Length; i++)
              			{
              				Console.WriteLine(sorted_sizes_array[i]);
              			}
              
              			Console.WriteLine("Press any key to continue...");
              			Console.ReadKey(true);
              		}
              	}
              }
              Hopefully this didn't violate any rules... :)

              Comment

              • SammyB
                Recognized Expert Contributor
                • Mar 2007
                • 807

                #8
                Originally posted by DarrenW
                Hopefully this didn't violate any rules... :)
                Yikes!! It only violates the rule of not reinventing the wheel. You really only need to write your own IComparer Interface and then let VB.NET use it to sort the items:
                Code:
                Public Class Form1
                	Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
                		Dim c As List(Of String)
                		c = New List(Of String)
                		' Add clothes to the list
                		c.Sort(New sortClothes)
                	End Sub
                End Class
                Public Class sortClothes : Implements IComparer
                	Public Function Compare(ByVal x As Object, ByVal y As Object) As Integer Implements System.Collections.IComparer.Compare
                		' Need code here to parse out size & compare them
                	End Function
                End Class
                For more details and a better explanation, see http://samples.gotdotnet.com/quickst.../doc/sort.aspx

                Comment

                • DarrenW
                  New Member
                  • Mar 2007
                  • 5

                  #9
                  I thought of that at one point but I could not find a way to allow the code to specify valid size tokens using that method. The sorter itself needs its own class to allow rules.

                  Comment

                  • bobneedshelp
                    New Member
                    • Feb 2007
                    • 17

                    #10
                    why not use an enum and sort by numbers?

                    Comment

                    • RedSon
                      Recognized Expert Expert
                      • Jan 2007
                      • 4980

                      #11
                      Originally posted by bobneedshelp
                      why not use an enum and sort by numbers?
                      I think the point of not using an enum would be that it would limit the number of mappings from strings to numbers. The program would then not accept both XSM and X-SMALL.

                      Comment

                      Working...