public static IList<int> GetInvalidNearbyTicketValuesForAllFields(TicketData ticketData)
 {
     var result = new List<int>();
     foreach (var nearbyTicket in ticketData.NearbyTickets)
     {
         foreach (var value in nearbyTicket.FieldValues)
         {
             var isValid = GetIsValidValueForAnyField(value, ticketData.TicketFields);
             if (!isValid)
             {
                 result.Add(value);
             }
         }
     }
     return result;
 }
        public static TicketData ParseInputLines(IList<string> inputLines)
        {
            var ticketFieldInputLines = new List<string>();
            var yourTicketInputLine = string.Empty;
            var nearbyTicketInputLines = new List<string>();
            bool isProcessingYourTicket = false;
            bool isProcessingNearbyTickets = false;
            foreach (var inputLine in inputLines)
            {
                if (string.IsNullOrWhiteSpace(inputLine))
                    continue;
                if (isProcessingYourTicket)
                {
                    if ("nearby tickets:".Equals(inputLine))
                    {
                        isProcessingYourTicket = false;
                        isProcessingNearbyTickets = true;
                        continue;
                    }
                    yourTicketInputLine = inputLine;
                }
                else if (isProcessingNearbyTickets)
                {
                    nearbyTicketInputLines.Add(inputLine);
                }
                else
                {
                    if ("your ticket:".Equals(inputLine))
                    {
                        isProcessingYourTicket = true;
                        continue;
                    }
                    ticketFieldInputLines.Add(inputLine);
                }
            }

            var ticketFields = ParseTicketFieldInputLines(ticketFieldInputLines);
            var yourTicket = ParseTicketInputLine(yourTicketInputLine);
            var nearbyTickets = ParseTicketInputLines(nearbyTicketInputLines);
            var result = new TicketData(ticketFields, yourTicket, nearbyTickets);
            return result;
        }
 public static IList<Ticket> GetNearbyTicketsWithNoInvalidValues(TicketData ticketData)
 {
     var result = new List<Ticket>();
     foreach (var nearbyTicket in ticketData.NearbyTickets)
     {
         bool isInvalidTicket = false;
         foreach (var value in nearbyTicket.FieldValues)
         {
             var isValid = GetIsValidValueForAnyField(value, ticketData.TicketFields);
             if (!isValid)
             {
                 isInvalidTicket = true;
                 break;
             }
         }
         if (!isInvalidTicket)
         {
             result.Add(nearbyTicket);
         }
     }
     return result;
 }
 public static Dictionary<string, int> GetFieldIndexes(TicketData ticketData)
 {
     var result = new Dictionary<string, int>();
     var validTickets = GetNearbyTicketsWithNoInvalidValues(ticketData);
     var indexTicketFieldCandidates = new Dictionary<int, IList<TicketField>>();
     for (int fieldIndex = 0; fieldIndex < ticketData.TicketFields.Count; fieldIndex++)
     {
         var possibleTicketFields = GetTicketFieldsThatWorkForIndex(
             fieldIndex, 
             validTickets, 
             ticketData.TicketFields);
         indexTicketFieldCandidates[fieldIndex] = possibleTicketFields;
     }
     while (indexTicketFieldCandidates.Count > 0)
     {
         var currentCandidate = indexTicketFieldCandidates
             .OrderBy(kvp => kvp.Value.Count)
             .First();
         if (currentCandidate.Value.Count != 1)
         {
             throw new Exception("Non-deterministic candidate found");
         }
         var fieldIndex = currentCandidate.Key;
         var ticketField = currentCandidate.Value[0];
         result[ticketField.Name] = fieldIndex;
         indexTicketFieldCandidates.Remove(fieldIndex);
         foreach (var kvp in indexTicketFieldCandidates)
         {
             kvp.Value.Remove(ticketField);
         }
         foreach (var kvp in indexTicketFieldCandidates)
         {
             if (kvp.Value.Count == 0)
                 indexTicketFieldCandidates.Remove(kvp.Key);
         }
     }
     
     return result;
 }