How do I get rid of circular numbers in my list

限于喜欢 提交于 2019-12-08 09:02:33
Slai

Here is my easy and inefficient way that should work with minimal changes to your code. It requires shared string list var strList = new List<string>(); to store the used numbers. Then this part:

foreach (var item in toric_class)
{
    Console.Write(item.ToString());
}
Console.Write(Environment.NewLine);
number_of_perms++; 

becomes something like this:

string strItem = " " + string.Join(" ", toric_class) + " "; // Example: int[] {1, 12, 123} becomes " 1 12 123 "

if (!strList.Any(str => str.Contains(strItem))) // Example: if " 1 12 123 1 12 123 " contains " 1 12 123 "
{
    Console.WriteLine(strItem);

    strItem += strItem.Substring(1); // double the string, but keep only one space between them
    strList.Add(strItem);
}

number_of_perms++; // not sure if this should be in the if statement

The idea is that for example the string " 1 1 1 2 5 2 1 1 1 2 5 2 " contains all circular copies of the numbers {1, 1, 1, 2, 5, 2}. I used string as a lazy way to check if array contains sub-array, but you can use similar approach to store copy of the used numbers in a list of arrays new List<int[]>() and check if any of the arrays in the list is circular copy of the current array, or even better HashSet<int[]>() approach similar to @slavanap's answer.


The first version of my answer was the easiest, but it works only with array of single digit items.

List is almost the same as array (new List<string>() instead of new string[]), but makes it much easier and efficient to add items to it. For example {1,2}.Add(3) becomes {1,2,3}.

str => str.Contains(strItem) is shortcut for a function that accepts parameter str and returns the result of str.Contains(strItem). That "function" is then passed to the .Any LINQ extension, so

strList.Any(str => str.Contains(strItem))

is shortcut for something like this:

foreach(string str in strList)
{
    if (str.Contains(strItem)) 
    {
        return true;
    }
}
return false;

The following method:

private static List<int> GetCircularEquivalents(int value)
{
    var circularList = new List<int>();
    var valueString = value.ToString();
    var length = valueString.Length - 1;

    for (var i = 0; i < length; i++)
    {
        valueString = valueString.Substring(1, length) + valueString.Substring(0, 1);
        circularList.Add(int.Parse(valueString));
    }

    return circularList;
}

will return a list of the circular numbers derived from the input value. Using your example, this method can be called like this:

var circularList = GetCircularEquivalents(111262);
var dirtyList = new List<int> { 1, 112621, 2, 126211, 3, 262111, 4, 621112, 5, 211126, 6 };
var cleanList = dirtyList.Except(circularList).ToList();

which would result in a cleanList made up of the numbers 1 through 6, i.e. the dirtyList with all the circular numbers derived from 111262 removed.

That's where OOP really benefits. Comments inlined.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication3 {

    struct MyInt : IEquatable<MyInt> {
        private int _value;

        public MyInt(int value) {
            _value = value;
        }

        // make it look like int
        static public implicit operator MyInt(int value) {
            return new MyInt(value);
        }
        public static explicit operator int(MyInt instance) {
            return instance._value;
        }

        // main difference in these 3 methods
        private int GetDigitsNum() {
            int temp, res;
            for (res = 0, temp = Math.Abs(_value); temp > 0; ++res, temp /= 10);
            return res;
        }
        public bool Equals(MyInt other) {
            int digits = other.GetDigitsNum();
            if (digits != this.GetDigitsNum())
                return false;
            int temp = other._value;

            // prepare mul used in shifts
            int mul = 1;
            for (int i = 0; i < digits - 1; ++i)
                mul *= 10;

            // compare
            for (int i = 0; i < digits; ++i) {
                if (temp == _value)
                    return true;
                // ROR
                int t = temp % 10;
                temp = temp / 10 + t * mul;
            }
            return false;
        }
        public override int GetHashCode() {
            // hash code must be equal for "equal" items,
            // that's why use a sum of digits.
            int sum = 0;
            for (int temp = _value; temp > 0; temp /= 10)
                sum += temp % 10;
            return sum;
        }

        // be consistent
        public override bool Equals(object obj) {
            return (obj is MyInt) ? Equals((MyInt)obj) : false;
        }
        public override string ToString() {
            return _value.ToString();
        }
    }

    class Program {
        static void Main(string[] args) {

            List<MyInt> list = new List<MyInt> { 112621, 126211, 262111, 621112, 211126 };
            // make a set of unique items from list
            HashSet<MyInt> set = new HashSet<MyInt>(list);

            // print that set    
            foreach(int item in set)
                Console.WriteLine(item);

        }
    }
}

Output: 112621

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!