English 中文(简体)
Linq - 阵列中连续数
原标题:Linq - getting consecutive numbers in an array
  • 时间:2012-01-13 16:22:52
  •  标签:
  • c#
  • linq

我正在建立一个掩体系统,我目前正在精简我的手计算器。

下述法典:

public enum CARDS
{
    None = 0,
    Two,
    Three,
    Four,
    Five,
    Six,
    Seven,
    Eight,
    Nine,
    Ten,
    Jack,
    Queen,
    King,
    Ace
};

public enum SUITS
{
    None = 0,
    Diamonds,
    Clubs,
    Hearts,
    Spades
};

public class Card
{
    public CARDS Val { get; set; }
    public SUITS Suit { get; set; }
}

public class IntIndex
{
    public int Count { get; set; }
    public int Index { get; set; }
}

static void Test()
{
    List<Card> cardList = new List<Card>();
    cardList.Add(new Card { Suit = SUITS.Diamonds, Val = CARDS.Two });
    cardList.Add(new Card { Suit = SUITS.Hearts, Val = CARDS.Four });
    cardList.Add(new Card { Suit = SUITS.Clubs, Val = CARDS.Five });
    cardList.Add(new Card { Suit = SUITS.Diamonds, Val = CARDS.Six });
    cardList.Add(new Card { Suit = SUITS.Spades, Val = CARDS.Six });
    cardList.Add(new Card { Suit = SUITS.Hearts, Val = CARDS.Seven });
    cardList.Add(new Card { Suit = SUITS.Clubs, Val = CARDS.Eight });

    // I have a processor that iterates through the above card list and creates
    // the following array based on the Card.Val as an index
    int[] list = new int[] {0,0,0,1,1,2,1,1,0,0,1,0,0,0};
    List<IntIndex> indexList =
        list.Select((item, index) => new IntIndex { Count = item, Index = index })
        .Where(c => c.Count > 0).ToList();

    List<int> newList = (from i in indexList
                         join j in indexList on i.Index equals j.Index + 1
                         where j.Count > 0
                         select i.Index).ToList();

    // Add the previous index since the join only works on n+1
    // Note - Is there a way to include the first comparison card?
    newList.Insert(0, newList[0] - 1);

    // Nice! - got my straight card list
    List<CARDS> cards = (from l in newList
                         select (CARDS)l).ToList();
}

However, I want to make it more compact as in:

static void Test()
{
    List<Card> cardList = new List<Card>();
    cardList.Add(new Card { Suit = SUITS.Diamonds, Val = CARDS.Two });
    cardList.Add(new Card { Suit = SUITS.Hearts, Val = CARDS.Four });
    cardList.Add(new Card { Suit = SUITS.Clubs, Val = CARDS.Five });
    cardList.Add(new Card { Suit = SUITS.Diamonds, Val = CARDS.Six });
    cardList.Add(new Card { Suit = SUITS.Spades, Val = CARDS.Six });
    cardList.Add(new Card { Suit = SUITS.Hearts, Val = CARDS.Seven });
    cardList.Add(new Card { Suit = SUITS.Clubs, Val = CARDS.Eight });

    List<Card> newList1 = (from i in cardList
                           join j in cardList on i.Val equals j.Val + 1
                           select i).ToList();

    // Add the previous index since the join only works on n+1
    // Similar to: newList1.Insert(0, newList1[0] - 1);
    // However, newList1 deals with Card objects so I need
    // To figure how to get the previous, non-duplicate card
    // from the original cardList (unless there is a way to return the
    // missing card!)
}

The problem is that the Sixes are being repeated. Distinct as well as a custom compare function does not work since this will break the n+1 join clause.

另一个问题是:

    List<Card> cardList = new List<Card>();
    cardList.Add(new Card { Suit = SUITS.Diamonds, Val = CARDS.Two });
    cardList.Add(new Card { Suit = SUITS.Hearts, Val = CARDS.Three });
    cardList.Add(new Card { Suit = SUITS.Clubs, Val = CARDS.Five });
    cardList.Add(new Card { Suit = SUITS.Diamonds, Val = CARDS.Six });
    cardList.Add(new Card { Suit = SUITS.Spades, Val = CARDS.Six });
    cardList.Add(new Card { Suit = SUITS.Hearts, Val = CARDS.Seven });
    cardList.Add(new Card { Suit = SUITS.Clubs, Val = CARDS.Eight });
    cardList.Add(new Card { Suit = SUITS.Diamonds, Val = CARDS.Jack });

我收到3头、6Diamond、7头、8头和3头等返回名单。

我确实想要的是一份清单,其中连续5张或更多或更妥善的卡片连续不断。 因此,上述名单将空出,因为投入名单上没有连续5张卡。

最佳回答

St! 当最快速的肥料是一种简单的比照面罩时,我对使用LINQ感到担忧:

    List<Card> cardList = new List<Card>();
    cardList.Add(new Card { Suit = SUITS.Diamonds, Val = RANK.Two });
    cardList.Add(new Card { Suit = SUITS.Hearts, Val = RANK.Three });
    cardList.Add(new Card { Suit = SUITS.Clubs, Val = RANK.Five });
    cardList.Add(new Card { Suit = SUITS.Diamonds, Val = RANK.Seven });
    cardList.Add(new Card { Suit = SUITS.Hearts, Val = RANK.Four });
    cardList.Add(new Card { Suit = SUITS.Clubs, Val = RANK.King });
    cardList.Add(new Card { Suit = SUITS.Diamonds, Val = RANK.Ace });

    int card = 0;
    foreach (Card c in cardList)
    {
        card |= 1 << (int)c.Val - 1;
    }

    bool isStraight = false;
    RANK high = RANK.Five;
    int mask = 0x1F;
    while (mask < card)
    {
        ++high;

        if ((mask & card) == mask)
        {
            isStraight = true;
        }
        else if (isStraight)
        {
            --high;
            break;
        }

        mask <<= 1;
    }

    // Check for Ace low
    if ((!isStraight) && ((0x100F & card) == 0x100F))
    {
        isStraight = true;
        high = RANK.Five;
    }

    return card;
问题回答

如果你有兴趣从<条码>卡片/条码>中获取最大系列连续卡值的卡片,无论是否合适,都会考虑这种做法。

//Extension method to find a subset of sequential consecutive elements with at least the specified count of members.
//Comparisions are based on the field value in the selector.
//Quick implementation for purposes of the example...
//Ignores error and bounds checking for purposes of example.  
//Also assumes we are searching for descending consecutive sequential values.
public static IEnumerable<T> FindConsecutiveSequence<T>(this IEnumerable<T> sequence, Func<T, int> selector, int count)
{
    int start = 0;
    int end = 1;
    T prevElement = sequence.First();

    foreach (T element in sequence.Skip(1))
    {
        if (selector(element) + 1 == selector(prevElement))
        {
            end++;
            if (end - start == count)
            {
                return sequence.Skip(start).Take(count);
            }
        }
        else
        {
            start = end;
            end++;
        }

        prevElement = element;
    }
    return sequence.Take(0);
}


//Compares cards based on value alone, not suit.
//Again, ignores validation for purposes of quick example.
public class CardValueComparer : IEqualityComparer<Card>
{
    public bool Equals(Card x, Card y)
    {
        return x.Val == y.Val ? true : false;
    }
    public int GetHashCode(Card c)
    {
        return c.Val.GetHashCode();
    }
}

鉴于上述情况,将首先根据卡片的价值而不是照样对卡进行分类,按 des令给你。 之后,又建立了一套不同的卡片子,再次以卡片价值为基础,不合适。 然后打电话到。 FindConsecutiveSequence specified the Val property for comparative and the amount of elements You need for a valid series.

//Sort in descending order based on value of the card.
cardList.Sort((x,y) => y.Val.CompareTo(x.Val));

//Create a subset of distinct card values.
var distinctCardSet = cardList.Distinct(new CardValueComparer());

//Create a subset of consecutive sequential cards based on value, with a minimum of 5 cards.
var sequentialCardSet = distinctCardSet.FindConsecutiveSequence(p => Convert.ToInt32(p.Val), 5);

我认为,这应当涵盖你在此问题上所询问的内容,并给你一些东西。 然而,如果对掩体而言,如果Ace可能是低价值,那么这一逻辑就会失败;{A,2,3,4,5}。 我只字不提需要的具体逻辑,因此也许你在问题范围之外处理。

Order the Cards by Number then Take 1 and Skip 3 of them to select what you want.

这是你们想要的吗?

第一是随机抽样清单,但顺序是卡片价值清单

Random random = new Random((int)(DateTime.Now.ToBinary() % Int32.MaxValue));
List<Card> hand = new List<Card>();

for(int card = (int)CARDS.Five;card <= (int)CARDS.Nine;card++)
{
    SUIT suit = (SUITS)(random.Next(4)+1);
    hand.Add(new Card { Suit = suit, Val = (CARDS)card });
}

Or a sequential list of suits would be...

for(int card = (int)CARDS.Five, int suit = (int)SUITS.Diamonds;card <= (int)CARDS.Nine;card++, suit++)
{
    if(suit > (int)SUITS.Spades)
        suit = (int)SUITS.Diamonds;
    hand.Add(new Card { Suit = (SUITS)suit, Val = (CARDS)card });
}

使用。 您可以修改以下实例代码,以退还各种卡片清单的长度,并修改规定,以检查必须配对的卡数量。 (例如,我对账面=5,你可以检查“数字”=5,等等)

public class Card {
    public CARDS Val { get; set; }
    public SUITS Suit { get; set; }

    // added ToString for program below
    public override string ToString() {
        return string.Format("{0} of {1}", Val, Suit);
    }
}

class Program {

    static IEnumerable<Card> RandomList(int size) {
        var r = new Random((int)DateTime.Now.Ticks);
        var list = new List<Card>();
        for (int i = 0; i < size; i++) {
            list.Add(new Card {
                Suit = (SUITS)r.Next((int)SUITS.Diamonds, (int)SUITS.Spades),
                Val = (CARDS)r.Next((int)CARDS.Two, (int)CARDS.Ace)
            });
        }
        return list.OrderBy(c => c.Val);
    }

    // generates a random list of 5 cards untill
    // the are in sequence, and then prints the
    // sequence
    static void Main(string[] args) {

        IEnumerable<Card> consecutive = null;

        do {
            // generate random list
            var hand = RandomList(5);

            // Aggreate:
            // the passed in function is run for each item
            // in hand. acc is the accumulator value.
            // It is passed in to each call. The new List<Card>()
            // parameter is the initial value of acc when the lambda
            // is called on the first item in the list

            // in the lambda we are checking to see if the last
            // card in the accumulator value is one less
            // than the current card. If so, add it to the
            // accumulator, otherwise do not.
            consecutive = hand.Aggregate(new List<Card>(), (acc, card) => {
                var size = acc.Count != 0
                    ? ((int)card.Val) - ((int)acc[acc.Count - 1].Val)
                    : 1;
                if (size == 1)
                    acc.Add(card);
                return acc;
            });
        } while (consecutive.Count() != 5);
        foreach (var card in consecutive) {
            Console.WriteLine(card);
        }
        Console.ReadLine();
    }
}

在提供七张贺卡(包括A-5)时,以下方法应最直截了当,但我先验。

关键要点是,如果你将卡片分解成 des令,删除任何重复价值,那么只有几种可能的办法可以直接安排(而且你只需要检查遗物):

  • If the first and fifth cards are four apart, they represent the highest straight (since we know the cards between them have no duplicate values).
  • The same is true, in order, for the second and sixth cards and for the third and seventh cards (if there are that many unique values left).
  • The only other possibility is if we have an Ace at the start of the sorted list and the cards Five to Two at the end, representing a A-5 straight.

Here s the code:

public static IEnumerable<Card> GetBestStraight(IEnumerable<Card> sevenCards)
{
    if (sevenCards.Count() != 7)
    {
        throw new ArgumentException("Wrong number of cards", "sevenCards");
    }

    List<Card> ordered = sevenCards.OrderByDescending(c => c.Val).ToList();
    List<Card> orderedAndUnique = ordered.Where((c, i) => i == 0 || ordered[i].Val != ordered[i - 1].Val).ToList();

    if (orderedAndUnique.Count < 5)
    {
        // not enough distinct cards for a straight
        return Enumerable.Empty<Card>();
    }

    if (orderedAndUnique[0].Val == orderedAndUnique[4].Val + 4)
    {
        // first five cards are a straight
        return orderedAndUnique.Take(5);
    }
    else if (5 < orderedAndUnique.Count && orderedAndUnique[1].Val == orderedAndUnique[5].Val + 4)
    {
        // next five cards are a straight
        return orderedAndUnique.Skip(1).Take(5);
    }
    else if (6 < orderedAndUnique.Count && orderedAndUnique[2].Val == orderedAndUnique[6].Val + 4)
    {
        // last five cards are a straight
        return orderedAndUnique.Skip(2).Take(5);
    }

    // if there s an A-5 straight, the above won t have found it (because Ace and Two are not consecutive in the enum)
    if (orderedAndUnique[0].Val == CARDS.Ace && orderedAndUnique[orderedAndUnique.Count - 4].Val == CARDS.Five)
    {
        return orderedAndUnique.Where(c => c.Val == CARDS.Ace || c.Val <= CARDS.Five);
    }

    return Enumerable.Empty<Card>();
}




相关问题
Anyone feel like passing it forward?

I m the only developer in my company, and am getting along well as an autodidact, but I know I m missing out on the education one gets from working with and having code reviewed by more senior devs. ...

NSArray s, Primitive types and Boxing Oh My!

I m pretty new to the Objective-C world and I have a long history with .net/C# so naturally I m inclined to use my C# wits. Now here s the question: I feel really inclined to create some type of ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

How to Use Ghostscript DLL to convert PDF to PDF/A

How to user GhostScript DLL to convert PDF to PDF/A. I know I kind of have to call the exported function of gsdll32.dll whose name is gsapi_init_with_args, but how do i pass the right arguments? BTW, ...

Linqy no matchy

Maybe it s something I m doing wrong. I m just learning Linq because I m bored. And so far so good. I made a little program and it basically just outputs all matches (foreach) into a label control. ...

热门标签