Wednesday, March 15, 2017

Evaluating an expression

Leaving a note to myself - a simple algorithm for evaluating expressions, no unary operators or parentheses.
phase 1 (tokenizer)

'+' => op1, add
'-' => op1, sub
'*' => op2, mul
'/' => op2, div
\d+ => number, value

phase 2 (evaluator)

tuple = first (number, op2, number)
while tuple:
  replace tuple with result of op2

tuple = first (number, op1, number)
while tuple:
  replace tuple with result of op1

there should be a single item left, a number; return its value

Saturday, June 25, 2016

Returning an IEnumerable from a database

This is probably rather obvious, but... when returning an `IEnumerable` from a database, like the records from a table, don't do this:

using (var db = GetDatabase())
  return db.GetTable("Table1");

because it will throw an exception when trying to enumerate those records, since the database connection has already been disposed.

Don't do this either:

using (var db = GetDatabase())
  return db.GetTable("Table1").ToList();

because it will retrieve all records from the table, even if you only need a small subset.

A slightly better way is to do this:

using (var db = GetDatabase())
  foreach (var item in db.GetTable("Table1"))
    yield return item;

This way, the `Dispose` method doesn't get called until the enumeration is over and if you only `Take()` a limited number of records from the result, it won't load the whole table. On the other hand, if you only add `Where()` clauses to the result, it will still enumerate everything (the "where" doesn't get passed on to the database engine).

This is not perfect - it would be best if I could return an IQueryable so that additional filters get passed on to the database engine, but I haven't yet figured out how to do that.

Sunday, June 05, 2016

Aligning text

I needed to write some code in a console app to align what a user was saying, in case it was longer than a line (80 characters):

marcel: blah blah blah a lot of text that doesn't fit in 80 characters more blah
         blah blah
long_username: Contrary to popular belief, Lorem Ipsum is not simply random text
               . It has roots in a piece of classical Latin literature from 45 B
               C, making it over 2000 years old. Richard McClintock, a Latin pro
               fessor at Hampden-Sydney College in Virginia, looked up one of th

I wrote the code in two ways: an imperative, mutating style and a functional (recursive) style. I find the second one to be more elegant but since the entire project is something done as a hobby I don't much care about speed; your mileage might vary. I'm also quite certain the first method can be improved but… again, I don't need to do that so it doesn't get done.

As usual, use at your own risk, I don't care about copyrights, blah, blah. Oh, and the result will look bad if the text contains non-printable characters.

        private static string Align(string prefix, string text, int length = 80)
            Debug.Assert(prefix != null);
            Debug.Assert(text != null);
            Debug.Assert(length > prefix.Length);

            var prefixLength = prefix.Length;

            var sb = new StringBuilder();

                var limit = Math.Min(text.Length, length - prefixLength);

                var current = text.Substring(0, limit);
                sb.Append(prefix + current);

                prefix = new string(' ', prefixLength);
                text = text.Substring(limit);
            } while (text != "");

            return sb.ToString();

        private static string Align2(string prefix, string text, int length = 80)
            Debug.Assert(prefix != null);
            Debug.Assert(text != null);
            Debug.Assert(length > prefix.Length);

            var all = prefix + text;

            return all.Length <= length
                ? all
                : all.Substring(0, length) +
                  Align2(new string(' ', prefix.Length), all.Substring(length), length);

Hmm... I think this would be an interesting exercise if I wanted to hire programmers.