tags:

views:

157

answers:

3

I want to do this with a simple text box GUI for folks to paste into and re-copy. For example if it started like this:

Before

part #        QTY
CS01-111-111  3
CS02-222-222  3
CS03-333-111  3
CS03-333-333  3 

I'd like textBox1.text to sort anything pasted into it like this going by the first 4 digits only, but retaining the QTY value after it:

After:

part #        QTY
CS03-333-111  3
CS03-333-333  3
CS01-111-111  3
CS02-222-222  3

It has no numerical order or pattern, it is just the way it is needed, so I would have to specify all the 4 digit numbers and their order.

I only have about 20 4 digit numbers to code, so it will not be a problem to do this manually after I get a start. Thank you very much for reading.

UPDATE:

Ok I have used Guffa's solution (thanks Guffa!!) to help me come up with the below, but it keeps locking up. Any ideas what I can do? Thanks!

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        public class Comparer : IComparer<string>
        {

            private Dictionary<string, int> _order;

            public Comparer()
            {
                _order = new Dictionary<string, int>();
                _order.Add("CS01", 1);
                _order.Add("CS58", 2);
                _order.Add("CS11", 3);
            }

            public int Compare(string x, string y)
            {
                if (x.Length < 4 || y.Length < 4)
                    return x.CompareTo(y);
                if (!_order.ContainsKey(x.Substring(0, 4)) || !_order.ContainsKey(y.Substring(0, 4)))
                    return x.CompareTo(y);
                return _order[x.Substring(0, 4)].CompareTo(_order[y.Substring(0, 4)]);
            }
        }

        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            string[] items = textBox1.Text.Split(Environment.NewLine.ToCharArray());
            Array.Sort<string>(items, 0, items.Length, new Comparer());
            textBox1.Text = String.Join(Environment.NewLine, items);
        }
    }
}
+5  A: 

Create a comparer that contains a dictionary for how you want the strings sorted:

public class Comparer : IComparer<string> {

   private Dictionary<string, int> _order;

   public Comparer() {
      _order = new Dictionary<string, int>();
      _order.Add("03-33", 1);
      _order.Add("01-11", 2);
      _order.Add("02-22", 3);
   }

   public int Compare(string x, string y) {
      return _order[x.Substring(2, 5)].CompareTo(_order[y.Substring(2, 5)]);
   }

}

Then you can use the comparer in the Array.Sort method

string[] items = TheTextBox.Text.Split(new String[]{ Environment.NewLine});
Array.Sort<string>(items, 1, items.Length - 1, new Comparer());
TheTextBox.Text = String.Join(Environment.NewLine, items);
Guffa
Is the Dictionary necessary? Why couldn't you create a Comparer without it?
Corey Sunwold
@Corey: It's not necessary, you can of course map the strings against a sort value in many different way. A Dictionary is easy to add more strings to, it has a very fast lookup and it scales very well.
Guffa
+2  A: 

It's locking up because you're changing textBox1.Text inside the textBox1_TextChanged method. So every time textBox1_TextChanged finishes, it gets called again with the new Text value.

You need something like this:

private bool _updating = false;
private void textBox1_TextChanged(object sender, EventArgs e)
{
    if (!_updating)
    {
        try
        {
            _updating = true;

            // do work ...

            textBox1.Text = ...
        }
        finally
        {
            _updating = false;
        }            
    }
}

or you could just check the value before you change textBox1.Text:

string newValue = ... ;
if (textBox1.Text != newValue)
{
    textBox1.Text = newValue;
}
Neil Whitaker
+2  A: 

Here are a couple of more modifications.

The constructor changes may or may not work for you, but could save you some typing.

This Compare method should be almost twice as fast, because it does half as many Dictionary look-ups.

public class Comparer : IComparer<string>
{

    private Dictionary<string, int> _order;

    public Comparer()
    {
        List<string> list = new List<string>()
        {
            "CS01",
            "CS58",
            "CS11"
        };

        _order = new Dictionary<string, int>();
        for (int i = 0; i < list.Count; i++)
        {
            _order.Add(list[i], i);
        }
    }

    public int Compare(string x, string y)
    {
        if (x.Length < 4 || y.Length < 4)
            return x.CompareTo(y);

        string xPrefix = x.Substring(0, 4);
        string yPrefix = y.Substring(0, 4);

        int xSequence;
        int ySequence;
        if (_order.TryGetValue(xPrefix, out xSequence)
            && _order.TryGetValue(yPrefix, out ySequence))
        {
            return xSequence.CompareTo(ySequence);
        }
        else
        {
            return x.CompareTo(y);
        }
    }
}
Neil Whitaker
This worked for me. THANK YOU and everyone else!!
Saintjah
@Saintjah if this solution worked for you, then please mark it as the accepted answer.
Waleed Al-Balooshi