Asked  7 Months ago    Answers:  5   Viewed   46 times

I have and old(ish) C# method I wrote that takes a number and converts it to any base:

string ConvertToBase(int number, char[] baseChars);

It's not all that super speedy and neat. Is there a good, known way of achieving this in .NET?

I'm looking for something that allows me to use any base with an arbitrary string of characters to use.

This only allows bases 16, 10, 8 and 2:

Convert.ToString(1, x);

I want to use this to achieve a massively high base taking advantage of numbers, all lower case and all upper case letters. Like in this thread, but for C# not JavaScript.

Does anyone know of a good and efficient way of doing this in C#?

 Answers

15

Convert.ToString can be used to convert a number to its equivalent string representation in a specified base.

Example:

string binary = Convert.ToString(5, 2); // convert 5 to its binary representation
Console.WriteLine(binary);              // prints 101

However, as pointed out by the comments, Convert.ToString only supports the following limited - but typically sufficient - set of bases: 2, 8, 10, or 16.

Update (to meet the requirement to convert to any base):

I'm not aware of any method in the BCL which is capable to convert numbers to any base so you would have to write your own small utility function. A simple sample would look like that (note that this surely can be made faster by replacing the string concatenation):

class Program
{
    static void Main(string[] args)
    {
        // convert to binary
        string binary = IntToString(42, new char[] { '0', '1' });

        // convert to hexadecimal
        string hex = IntToString(42, 
            new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
                         'A', 'B', 'C', 'D', 'E', 'F'});

        // convert to hexavigesimal (base 26, A-Z)
        string hexavigesimal = IntToString(42, 
            Enumerable.Range('A', 26).Select(x => (char)x).ToArray());

        // convert to sexagesimal
        string xx = IntToString(42, 
            new char[] { '0','1','2','3','4','5','6','7','8','9',
            'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
            'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x'});
    }

    public static string IntToString(int value, char[] baseChars)
    {
        string result = string.Empty;
        int targetBase = baseChars.Length;

        do
        {
            result = baseChars[value % targetBase] + result;
            value = value / targetBase;
        } 
        while (value > 0);

        return result;
    }

    /// <summary>
    /// An optimized method using an array as buffer instead of 
    /// string concatenation. This is faster for return values having 
    /// a length > 1.
    /// </summary>
    public static string IntToStringFast(int value, char[] baseChars)
    {
        // 32 is the worst cast buffer size for base 2 and int.MaxValue
        int i = 32;
        char[] buffer = new char[i];
        int targetBase= baseChars.Length;

        do
        {
            buffer[--i] = baseChars[value % targetBase];
            value = value / targetBase;
        }
        while (value > 0);

        char[] result = new char[32 - i];
        Array.Copy(buffer, i, result, 0, 32 - i);

        return new string(result);
    }
}

Update 2 (Performance Improvement)

Using an array buffer instead of string concatenation to build the result string gives a performance improvement especially on large number (see method IntToStringFast). In the best case (i.e. the longest possible input) this method is roughly three times faster. However, for 1-digit numbers (i.e. 1-digit in the target base), IntToString will be faster.

Tuesday, June 1, 2021
 
ramdemon
answered 7 Months ago
95

The point is that the interface represents a contract. A set of public methods any implementing class has to have. Technically, the interface only governs syntax, i.e. what methods are there, what arguments they get and what they return. Usually they encapsulate semantics as well, although that only by documentation.

You can then have different implementations of an interface and swap them out at will. In your example, since every pizza instance is an IPizza you can use IPizza wherever you handle an instance of an unknown pizza type. Any instance whose type inherits from IPizza is guaranteed to be orderable, as it has an Order() method.

Python is not statically-typed, therefore types are kept and looked up at runtime. So you can try calling an Order() method on any object. The runtime is happy as long as the object has such a method and probably just shrugs and says »Meh.« if it doesn't. Not so in C#. The compiler is responsible for making the correct calls and if it just has some random object the compiler doesn't know yet whether the instance during runtime will have that method. From the compiler's point of view it's invalid since it cannot verify it. (You can do such things with reflection or the dynamic keyword, but that's going a bit far right now, I guess.)

Also note that an interface in the usual sense does not necessarily have to be a C# interface, it could be an abstract class as well or even a normal class (which can come in handy if all subclasses need to share some common code – in most cases, however, interface suffices).

Sunday, June 6, 2021
 
juanrpozo
answered 6 Months ago
95

That was kind of an interesting question, so I went a little overboard:

class Integer
  def to_base(base=10)
    return [0] if zero?
    raise ArgumentError, 'base must be greater than zero' unless base > 0
    num = abs
    return [1] * num if base == 1
    [].tap do |digits|
      while num > 0
        digits.unshift num % base
        num /= base
      end
    end
  end
end

This works for arbitrary bases. It only works for integers, although there is no reason why it couldn't be extended to work with any arbitrary number. Also, it ignores the sign of the number. Again, there is no reason why it must do that, but mainly I didn't want to have to come up with a convention for returning the sign in the return value.

class Integer
  old_to_s = instance_method(:to_s)
  define_method :to_s do |base=10, mapping=nil, sep=''|
    return old_to_s.bind(self).(base) unless mapping || base > 36
    mapping ||= '0123456789abcdefghijklmnopqrstuvwxyz'
    return to_base(base).map {|digit| mapping[digit].to_s }.join(sep)
  end
end

[Fixnum, Bignum].each do |klass|
  old_to_s = klass.instance_method(:to_s)
  klass.send :define_method, :to_s do |base=10, mapping=nil, sep=''|
    return old_to_s.bind(self).(base) unless mapping || base > 36
    return super(base, mapping, sep) if mapping
    return super(base)
  end
end

I also extended the to_s method so that it works with bases greater than 36. If you want to use a base greater than 36, you have to pass in a mapping object which maps the "digits" to strings. (Well, actually, all that is required is that you provide an object that responds to [] and returns something which responds to to_s. So, a string is perfect, but e.g. an array of integers also works.)

It also accepts an optional separator, which is used to separate the digits.

For example, this allows you to format an IPv4 address by treating it as a base-256 number and using the identity for the mapping and '.' as the separator:

2_078_934_278.to_s(256, Array.new(256) {|i| i }, '.') # => '123.234.5.6'

Here's an (incomplete) testsuite:

require 'test/unit'
class TestBaseConversion < Test::Unit::TestCase
  def test_that_83992_in_base_85_is_11_53_12
    assert_equal [11, 53, 12], 83992.to_base(85)
  end
  def test_that_83992_in_base_37_is_1_24_13_2
    assert_equal [1, 24, 13, 2], 83992.to_base(37)
  end
  def test_that_84026_in_base_37_is_1_24_13_36
    assert_equal [1, 24, 13, 36], 84026.to_base(37)
  end
  def test_that_0_in_any_base_is_0
    100.times do |base|
      assert_equal [0], 0.to_base(base)
      assert_equal [0], 0.to_base(1 << base)
      assert_equal [0], 0.to_base(base << base)
    end
  end
  def test_that_84026_in_base_37_prints_1od_
    assert_equal '1od_', 84026.to_s(37, '0123456789abcdefghijklmnopqrstuvwxyz_')
  end
  def test_that_ip_address_formatting_works
    addr = 2_078_934_278
    assert_equal '123.234.5.6', addr.to_s(256, (0..255).to_a, '.')
    assert_equal '123.234.5.6', addr.to_s(256, Array.new(256) {|i| i}, '.')
  end
  def test_that_old_to_s_still_works
    assert_equal '84026', 84026.to_s
    assert_equal '1su2', 84026.to_s(36)
  end
end
Friday, July 30, 2021
 
Alix
answered 4 Months ago
89

You can ensure all requests have these query parameters by adding a custom RequestInterceptor to your RestAdapter

RequestInterceptor requestInterceptor = new RequestInterceptor()
{
    @Override
    public void intercept(RequestFacade request) {
        request.addQueryParam("app_version", "Version 1.x");
        request.addQueryParam("device_type", "Samsung S4");
    }
};

restAdapter.setRequestInterceptor(requestInterceptor)
Monday, August 9, 2021
 
Pradip
answered 4 Months ago
17

I am not sure what you want to achieve but the following compiles and runs without exceptions:

class Program
{
    static void Main(string[] args)
    {
        var holder = new Holder<IObject>();
        holder.MyItem = new Object { List = new List<IObject>() };
        holder.ChangeItemList(new Object { List = new List<IObject>() });
    }
}

public class Object : IObject
{
    public List<IObject> List { get; set; }
}

public interface IObject
{
    List<IObject> List { get; set; }
}

public class Holder<T> where T : IObject
{
    public T MyItem { get; set; }

    public void ChangeItemList(T item)
    {
        MyItem.List = item.List;
    }
}
Friday, September 3, 2021
 
Success Man
answered 3 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :
 
Share