Итерация через алфавит - C# a-caz

Вы можете просто сделать:

git log --oneline --decorate v0.1.0

... чтобы показать каждый коммит вплоть до v0.1.0 включительно. Конечно, git log позволяет также ограничивать коммиты, показанные любым из способов, которые понимает git rev-list, поэтому, если вы хотите увидеть только изменения между v0.0.9 и v0.1.0, вы также можете сделать:

git log --oneline --decorate v0.0.9..v0.1.0

Альтернативным выходом, который может быть полезен для этой цели, является git shortlog, в котором группируются и суммируются вклады каждого автора. Попробуйте, например:

git shortlog v0.1.0
16
задан Kindle Q 13 December 2017 в 09:35
поделиться

8 ответов

Редактировать: Сделано так, как того требует последняя редакция OP

Это простейшее решение и протестировано:

static void Main(string[] args)
{
    Console.WriteLine(GetNextBase26("a"));
    Console.WriteLine(GetNextBase26("bnc"));
}

private static string GetNextBase26(string a)
{
    return Base26Sequence().SkipWhile(x => x != a).Skip(1).First();
}

private static IEnumerable<string> Base26Sequence()
{
    long i = 0L;
    while (true)
        yield return Base26Encode(i++);
}

private static char[] base26Chars = "abcdefghijklmnopqrstuvwxyz".ToCharArray();
private static string Base26Encode(Int64 value)
{
    string returnValue = null;
    do
    {
        returnValue = base26Chars[value % 26] + returnValue;
        value /= 26;
    } while (value-- != 0);
    return returnValue;
}
22
ответ дан 30 November 2019 в 15:21
поделиться

First effort, with just a-z then aa-zz

public static IEnumerable<string> GetExcelColumns()
{
    for (char c = 'a'; c <= 'z'; c++)
    {
        yield return c.ToString();
    }
    char[] chars = new char[2];
    for (char high = 'a'; high <= 'z'; high++)
    {
        chars[0] = high;
        for (char low = 'a'; low <= 'z'; low++)
        {
            chars[1] = low;
            yield return new string(chars);
        }
    }
}

Note that this will stop at 'zz'. Of course, there's some ugly duplication here in terms of the loops. Fortunately, that's easy to fix - and it can be even more flexible, too:

Second attempt: more flexible alphabet

private const string Alphabet = "abcdefghijklmnopqrstuvwxyz";

public static IEnumerable<string> GetExcelColumns()
{
    return GetExcelColumns(Alphabet);
}

public static IEnumerable<string> GetExcelColumns(string alphabet)
{
    foreach(char c in alphabet)
    {
        yield return c.ToString();
    }
    char[] chars = new char[2];
    foreach(char high in alphabet)
    {
        chars[0] = high;
        foreach(char low in alphabet)
        {
            chars[1] = low;
            yield return new string(chars);
        }
    }
}

Now if you want to generate just a, b, c, d, aa, ab, ac, ad, ba, ... you'd call GetExcelColumns("abcd").

Third attempt (revised further) - infinite sequence

public static IEnumerable<string> GetExcelColumns(string alphabet)
{
    int length = 0;
    char[] chars = null;
    int[] indexes = null;
    while (true)
    {
        int position = length-1;
        // Try to increment the least significant
        // value.
        while (position >= 0)
        {
            indexes[position]++;
            if (indexes[position] == alphabet.Length)
            {
                for (int i=position; i < length; i++)
                {
                    indexes[i] = 0;
                    chars[i] = alphabet[0];
                }
                position--;
            }
            else
            {
                chars[position] = alphabet[indexes[position]];
                break;
            }
        }
        // If we got all the way to the start of the array,
        // we need an extra value
        if (position == -1)
        {
            length++; 
            chars = new char[length];
            indexes = new int[length];
            for (int i=0; i < length; i++)
            {
                chars[i] = alphabet[0];
            }
        }
        yield return new string(chars);
    }
}

It's possible that it would be cleaner code using recursion, but it wouldn't be as efficient.

Note that if you want to stop at a certain point, you can just use LINQ:

var query = GetExcelColumns().TakeWhile(x => x != "zzz");

"Restarting" the iterator

To restart the iterator from a given point, you could indeed use SkipWhile as suggested by thesoftwarejedi. That's fairly inefficient, of course. If you're able to keep any state between call, you can just keep the iterator (for either solution):

using (IEnumerator<string> iterator = GetExcelColumns())
{
    iterator.MoveNext();
    string firstAttempt = iterator.Current;

    if (someCondition)
    {
        iterator.MoveNext();
        string secondAttempt = iterator.Current;
        // etc
    }
}

Alternatively, you may well be able to structure your code to use a foreach anyway, just breaking out on the first value you can actually use.

29
ответ дан 30 November 2019 в 15:21
поделиться

Я знаю, что здесь много ответов, и один из них был принят, но, IMO, все они усложняют задачу, чем нужно. Я думаю, что следующее проще и понятнее:

static string NextColumn(string column){
    char[] c = column.ToCharArray();
    for(int i = c.Length - 1; i >= 0; i--){
        if(char.ToUpper(c[i]++) < 'Z')
            break;
        c[i] -= (char)26;
        if(i == 0)
            return "A" + new string(c);
    }
    return new string(c);
}

Обратите внимание, что это не выполняет никакой проверки ввода. Если вы не доверяете своим абонентам, вам следует добавить проверку IsNullOrEmpty в начале и c [i]> = 'A' && c [i] <= 'Z' | | c [i]> = 'a' && c [i] <= 'z' проверка в начале цикла. Или просто оставьте как есть и пусть будет GIGO .

Вы также можете найти применение этим вспомогательным функциям:

static string GetColumnName(int index){
    StringBuilder txt = new StringBuilder();
    txt.Append((char)('A' + index % 26));
    //txt.Append((char)('A' + --index % 26));
    while((index /= 26) > 0)
        txt.Insert(0, (char)('A' + --index % 26));
    return txt.ToString();
}
static int GetColumnIndex(string name){
    int rtn = 0;
    foreach(char c in name)
        rtn = rtn * 26 + (char.ToUpper(c) - '@');
    return rtn - 1;
    //return rtn;
}

Эти две функции отсчитываются от нуля. То есть «A» = 0, «Z» = 25, «AA» = 26 и т. Д. Чтобы сделать их основанными на единице (как интерфейс COM в Excel), удалите строку над строкой комментария в каждой функции и раскомментируйте эти строки.

Как и в случае с функцией NextColumn , эти функции не проверяют свои входные данные. Оба они дадут вам мусор, если они его получат.

3
ответ дан 30 November 2019 в 15:21
поделиться

Это похоже на отображение int, только с использованием базы 26 вместо базы 10. Попробуйте следующий алгоритм, чтобы найти n-я запись массива

q = n div 26;
r = n mod 26;
s = '';
while (q > 0 || r > 0) {
  s = alphabet[r] + s;
  q = q div 26;
  r = q mod 26;
}

Конечно, если вам нужны первые n записей, это не самое эффективное решение. В этом случае попробуйте что-то вроде решения Дэниела.

0
ответ дан 30 November 2019 в 15:21
поделиться

The following populates a list with the required strings:

List<string> result = new List<string>();
for (char ch = 'a'; ch <= 'z'; ch++){
    result.Add (ch.ToString());
}

for (char i = 'a'; i <= 'z'; i++)
{
    for (char j = 'a'; j <= 'z'; j++)
    {
        result.Add (i.ToString() + j.ToString());
    }
}
3
ответ дан 30 November 2019 в 15:21
поделиться

Я попробовал и придумал следующее:

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

namespace Alphabetty
{
    class Program
    {
        const string alphabet = "abcdefghijklmnopqrstuvwxyz";
        static int cursor = 0;
        static int prefixCursor;
        static string prefix = string.Empty;
        static bool done = false;
        static void Main(string[] args)
        {
            string s = string.Empty;
            while (s != "Done")
            {
                s = GetNextString();
                Console.WriteLine(s);
            }
            Console.ReadKey();

        }        
        static string GetNextString()
        {
            if (done) return "Done";
            char? nextLetter = GetNextLetter(ref cursor);
            if (nextLetter == null)
            {
                char? nextPrefixLetter = GetNextLetter(ref prefixCursor);
                if(nextPrefixLetter == null)
                {
                    done = true;
                    return "Done";
                }
                prefix = nextPrefixLetter.Value.ToString();
                nextLetter = GetNextLetter(ref cursor);
            }

            return prefix + nextLetter;
        }

        static char? GetNextLetter(ref int letterCursor)
        {
            if (letterCursor == alphabet.Length)
            {
                letterCursor = 0;
                return null;
            }

            char c = alphabet[letterCursor];
            letterCursor++;
            return c;
        }
    }
}
0
ответ дан 30 November 2019 в 15:21
поделиться

Вот моя попытка использовать рекурсию:

public static void PrintAlphabet(string alphabet, string prefix)
{
    for (int i = 0; i < alphabet.Length; i++) {
        Console.WriteLine(prefix + alphabet[i].ToString());
    }

    if (prefix.Length < alphabet.Length - 1) {
        for (int i = 0; i < alphabet.Length; i++) {
            PrintAlphabet(alphabet, prefix + alphabet[i]);
        }
    }
}

Затем просто вызовите PrintAlphabet ("abcd", "") ;

-2
ответ дан 30 November 2019 в 15:21
поделиться

просто любопытно, почему не только

    private string alphRecursive(int c) {
         var alphabet = "abcdefghijklmnopqrstuvwxyz".ToCharArray();
         if (c >= alphabet.Length) {
             return alphRecursive(c/alphabet.Length) + alphabet[c%alphabet.Length];
         } else {
             return "" + alphabet[c%alphabet.Length];
         }
    }
1
ответ дан 30 November 2019 в 15:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: