Sorting an array collection based on value of array in flex - sorting

I've been looking at sorting array collections. So far I've seen things like sorting numerically in ascending and descending order. What I'm looking for is to discover away to sort an arraycollection based on the order of values in another array.
For Example:
I have an array containing 10 numerical values. I also have an arraycollection. One of the properties of each arracycollection entry corresponds to one of the values in the former array.
I want to be able to sort the arraycollection based on the order of the values in the array.
Whats the best way to this?
I was thinking of looping through the first array, getting the first value, finding the entry in the arraycollection with that value and then adding it to a new arraycollection but it seems kinda long winded and I was hoping there might be a clever way to do it.
EDIT
This is what I've pieced together so far. Seems a bit too round about though
private function parseXML(xml:XML):void
{
var s:String=xml.toXMLString()
artistinfo=convertXmlToArrayCollection(s)
sort()
dispatchEvent(new XMLEvent(XMLEvent.XML_PARSED))
//artistinfo.sort()
}
private function clone(source:Object):*
{
var myBA:ByteArray=new ByteArray();
myBA.writeObject(source);
myBA.position=0;
return (myBA.readObject());
}
private function sort():void
{
var myAC:ArrayCollection=new ArrayCollection(clone(artistinfo.source));
//artistinfo=new ArrayCollection();
var amt:int=trackids.length;
var value:Number=0
var arr:*
var index:Number
for (var i:int=0; i < amt; i++)
{
value=trackids[i];
index=getItemIndexByProperty(myAC, "id", new String(value))
artistinfo[i]=myAC.getItemAt(index)
}
}
public function getItemIndexByProperty(array:ArrayCollection, property:String, value:String):Number
{
for (var i:Number=0; i < array.length; i++)
{
var obj:Object=Object(array[i])
if (obj[property].value == value)
return i;
}
return -1;
}

I'm going to add in my edit as the answer for now.
It may be useful for somebody who lands here from a search
If anybody can offer a more concise or better way please post!
private function parseXML(xml:XML):void
{
var s:String=xml.toXMLString()
artistinfo=convertXmlToArrayCollection(s)
sort()
dispatchEvent(new XMLEvent(XMLEvent.XML_PARSED))
//artistinfo.sort()
}
private function clone(source:Object):*
{
var myBA:ByteArray=new ByteArray();
myBA.writeObject(source);
myBA.position=0;
return (myBA.readObject());
}
private function sort():void
{
var myAC:ArrayCollection=new ArrayCollection(clone(artistinfo.source));
//artistinfo=new ArrayCollection();
var amt:int=trackids.length;
var value:Number=0
var arr:*
var index:Number
for (var i:int=0; i < amt; i++)
{
value=trackids[i];
index=getItemIndexByProperty(myAC, "id", new String(value))
artistinfo[i]=myAC.getItemAt(index)
}
}
public function getItemIndexByProperty(array:ArrayCollection, property:String, value:String):Number
{
for (var i:Number=0; i < array.length; i++)
{
var obj:Object=Object(array[i])
if (obj[property].value == value)
return i;
}
return -1;
}

Related

elastic, can I use my own global ordinals with a painless terms aggregation script?

Here's what one of my document might look like
{
"CC":{"colors":["Blue","Green","Yellow"]},
"CN":{"colors":["White","Green","Blue"]},
"WA":{"colors":["Orange","Green","Blue"]},
...
}
I want a terms aggregation, on the intersection of two fields CC.colors and CN.colors. That is, for this document, that field will have ["Green", "Blue"] in the intersection, and I want a term aggregation on this intersection.
As far as I understand, there are two ways to do it.
1) A painless script in terms aggregation, which returns the intersection of these two arrays for each document.
2) A new field created during index time, maybe called CC_CN.colors, which holds intersection for all docs.
I can't go ahead with 2 because my combinations will be too many. I can have any need during search time, like CC_CN, or CC_WA, or WA_CN_CC etc.
For 1), it works, but gets painfully slow. One reason is that 1) cannot use global ordinals.
Is there any trick, that I can ask elastic to build a custom global ordinal for my painless terms aggregation? I know there are just 25 colors in my system, so can give all colors to elastic somewhere, and "assure" them that I'll not return anything else but these colors from my aggregation?
Or, if I encode and store numbers instead of strings in index, would this be faster for elastic? e.g. 0 instead of "Black", 1 instead of "Green" etc.?
Other than intersection, my other use cases involve union etc. as well. Thanks for reading!
To answer it myself, we ended up asking for these arrays in _source and performing union/intersection in Ruby.
It is also possible to do this in painless, and that offers a bit better performance. Elastic uses map to do aggregation, and I couldn't figure out any way to use global ordinals. I don't think its possible.
We wrote code that generates painless code to perform intersection and union between arrays.
For any future wanderer, here's what the generated code looks like:
This is for union:
Stream stream = [].stream();
String[] stream_keys = new String[] {'CC.colors', 'CN.colors'};
for (int i = 0; i < stream_keys.length; ++i) {
if (doc.containsKey(stream_keys[i])) {
stream = Stream.concat(stream, doc[stream_keys[i]].stream());
}
}
stream = stream.distinct();
And this is for intersection (stream, list_0_stream and list_1_stream intersection):
List list_0 = list_0_stream.collect(Collectors.toList());
List list_1 = list_1_stream.collect(Collectors.toList());
return stream.filter(list_0::contains).filter(list_1::contains).toArray();
The performance seems to be acceptable.
There are 2 method offer to you
Cost alot of my time
^ ^
ColorMap={"Blue":0,"Green":1,"Yellow":2,"White":3,"Orange":4};
ReverseColorMap=["Blue","Green","Yellow","White","Orange"];
var All={
"CC":{"colors":["Blue","Green","Yellow"]},
"CN":{"colors":["White","Green","Blue"]},
"WA":{"colors":["Orange","Green","Blue"]}
};
//Cover Encode
function EncodeColor(T1){
var T2 = JSON.parse(JSON.stringify(T1));//Clone Original
for(var i in T2){
for(var j in T2[i]["colors"]){
T2[i]["colors"][j]=ColorMap[T2[i]["colors"][j]];
}
}
return T2;
}
var NewAll=EncodeColor(All);
console.log(All);
console.log(NewAll);
function SortColor(T1){
for(var i in T1){
T1[i]["colors"].sort((a, b) => {
return a-b;
});
}
}
function BuildSameColor(T1){
var CombineNew={};
var Name_Temp=[];
for(var i in T1){
Name_Temp.push(i);
}
for(var i =0;i<Name_Temp.length;i++){
for(var j =i+1;j<Name_Temp.length;j++){//j=i+1 because CC_CC not valid CC_CN is valid etc...
CombineNew[Name_Temp[i]+"_"+Name_Temp[j]]={"colors":T1[Name_Temp[i]]["colors"].concat(T1[Name_Temp[j]]["colors"])};//combine color array
}
}
SortColor(CombineNew);//Sort Result
//Sort will reduce compare time(later) when color is a lot
for(var i in CombineNew){
var NewAr=[];
for(var j=0;j<CombineNew[i]["colors"].length-1;j++){
if(CombineNew[i]["colors"][j]==CombineNew[i]["colors"][j+1]){
NewAr.push(CombineNew[i]["colors"][j]);
}
}
CombineNew[i]["colors"]=NewAr;
}
return CombineNew;
}
var TTT=BuildSameColor(NewAll);
console.log(TTT);
//Then Decode Color
function DecodeColor(T1){
var T2 = JSON.parse(JSON.stringify(T1));//Clone Original
for(var i in T2){
for(var j in T2[i]["colors"]){
T2[i]["colors"][j]=ReverseColorMap[T2[i]["colors"][j]];
}
}
return T2;
}
var TTTQQ=DecodeColor(TTT);
console.log(TTTQQ);
//This Also work any length of color
var Examp={
"CC":{"colors":["Blue","Green","Yellow","Orange"]},
"CN":{"colors":["White","Green","Blue"]},
"WA":{"colors":["Orange","Green","Blue"]}
};
var E_Examp=EncodeColor(Examp);
var Com_E_E_Examp=BuildSameColor(E_Examp);
var D_Examp=DecodeColor(Com_E_E_Examp);
console.log(D_Examp);
Enjoin it!!!!!!!!
ColorMap={"Blue":0,"Green":1,"Yellow":2,"White":3,"Orange":4};
ReverseColorMap=["Blue","Green","Yellow","White","Orange"];
var All={
"CC":{"colors":["Blue","Green","Yellow"]},
"CN":{"colors":["White","Green","Blue"]},
"WA":{"colors":["Orange","Green","Blue"]}
};
//Cover Encode
function EncodeColor(T1){
var T2 = JSON.parse(JSON.stringify(T1));//Clone Original
for(var i in T2){
for(var j in T2[i]["colors"]){
T2[i]["colors"][j]=ColorMap[T2[i]["colors"][j]];
}
}
return T2;
}
var NewAll=EncodeColor(All);
console.log(All);
console.log(NewAll);
function SortColor(T1){
for(var i in T1){
T1[i]["colors"].sort((a, b) => {
return a-b;
});
}
}
function StaticSearch(T1,Name1,Name2){
if(Name1 in T1 && Name2 in T1 ){
var Temp= T1[Name1]["colors"].concat(T1[Name2]["colors"]);
var T2=[];
Temp.sort((a, b) => {
return a-b;
});
for(var i=0;i<Temp.length-1;i++){
if(Temp[i]==Temp[i+1]){
T2.push(Temp[i]);
}
}
var ReturnObj={};
ReturnObj[Name1+"_"+ Name2]={};
ReturnObj[Name1+"_"+ Name2]["colors"]=T2;
return ReturnObj;
}
return null;
}
var SearchResult=StaticSearch(NewAll,"CC","CN");
console.log(SearchResult);
//Then Decode Color/*
function DecodeColor(T1){
var T2 = JSON.parse(JSON.stringify(T1));//Clone Original
for(var i in T2){
for(var j in T2[i]["colors"]){
T2[i]["colors"][j]=ReverseColorMap[T2[i]["colors"][j]];
}
}
return T2;
}
var TTTQQ=DecodeColor(SearchResult);
console.log(TTTQQ);
//This Also work any length of color
var Examp={
"CC":{"colors":["Blue","Green","Yellow","Orange"]},
"CN":{"colors":["White","Green","Blue"]},
"WA":{"colors":["Orange","Green","Blue"]}
};
var E_Examp=EncodeColor(Examp);
var Com_E_E_Examp=StaticSearch(E_Examp,"WA","CC");
var D_Examp=DecodeColor(Com_E_E_Examp);
console.log(D_Examp);
Another Method Static Search

Speed Up Find-and-Replace Google Apps Script Function for sheets

I've written a pretty simple script that successfully takes information from one sheet in a Google Spreadsheet, and replaces information in a column in another sheet in the same spreadsheet pending satisfaction of two criteria: the receiving row has the same "Customer ID" and "Product Type." I say "simple" because it's intuitive, but extremely computationally demanding (taking nearly 30 seconds to run!).
From what I've read online, it's the sequential read and write operations that are causing the slowdown. I'm assuming that if I sort the sheets in question on the two criteria and THEN do a function that writes over subsequent rows, I may be able to speed it up. I'm a little weak on algorithms, so I'm still scratching my head on how to do this elegantly.
Does anyone have any suggestions? Below is my original script, and I've already made sure that the spreadsheet collapses empty rows, so time isn't wasted iterating over nothing.
function replaceRawWithRepChanges(receivedSheet) {
var ss = SpreadsheetApp.openById(receivedSheet);
var repchanges = ss.getSheetByName('repchanges');
var rawSheet = ss.getSheetByName('Sheet1');
var rawTMtoReplace = rawSheet.getRange('P2:P');
var repCustID = repchanges.getRange('A1:A').getValues();
var repTM = repchanges.getRange('F1:F').getValues();
var repCategory = repchanges.getRange('G1:G').getValues();
var rawCustID = rawSheet.getRange('A2:A').getValues();
var rawTM = rawSheet.getRange('P2:P').getValues();
var rawCategory = rawSheet.getRange('U2:U').getValues();
var repInfo = [repCustID, repTM, repCategory];
var rawInfo = [rawCustID, rawTM, rawCategory];
for (var i=0; i < rawInfo[0].length; i++) {
for (var j=0; j < repInfo[0].length; j++) {
// var thisRawCust = rawInfo[0][i];
// var thisRepCust = repInfo[0][j];
if (rawInfo[0][i].toString() == repInfo[0][j].toString()) {
// var thisRawCategory = rawInfo[2][i];
// var thisRepCategory = repInfo[2][j];
if (rawInfo[2][i].toString() == repInfo[2][j].toString()) {
// var repvalue = repInfo[1][j];
rawInfo[1][i] = repInfo[1][j];
// var newRawValue = rawInfo[1][i];
}
}
}
}
return rawInfo[1];
}
Yes, you should sort the data (perhaps using the SORT command, which does work with multiple columns). Then, using two pointers, you only have to go down the columns once, rather than checking the entirety of repInfo for matches for every single row in rawInfo.
Once you've sorted the information, your loop might look like the following:
var i = 0;
var j = 0;
while (i < rawInfo[0].length && j < repInfo[0].length) {
if (rawInfo[0][i].toString() == repInfo[0][j].toString()) {
if (rawInfo[2][i].toString() == repInfo[2][j].toString()) {
rawInfo[1][i]=repInfo[1][j];
i++;
j++;
} else if (rawInfo[2][i].toString() < repInfo[2][j].toString()) {
i++;
} else {
j++;
}
} else if (rawInfo[0][i].toString() < repInfo[0][j].toString()) {
i++;
} else {
j++;
}
}

firebase sort reverse order

var playersRef = firebase.database().ref("team_mapping/");
playersRef.orderByChild("score").limitToFirst(7).on("child_added", function(data) {
}
Using this query, I can sort it in ascending order. But, I wanted to sort in descending order. Can any body suggest me with some way to do this. Any help will be appreciated.
Thanks in Advance!!
just use reverse() on the array , suppose if you are storing the values to an array items[] then do a this.items.reverse()
ref.subscribe(snapshots => {
this.items = [];
snapshots.forEach(snapshot => {
this.items.push(snapshot);
});
**this.items.reverse();**
},
You can limit to the last 7 which will give you the highest scores since the query is in ascending order. Then all you have to do is reverse the last 7 you get for them to be in descending order.
var playersRef = firebase.database().ref("team_mapping/");
var playersData = [];
var pageCursor;
playersRef.orderByChild("score").limitToLast(7).on("child_added", function(data) {
playersData = [data] + playersData;
}
UPDATE
Here is an example of how you could paginate by score.
const query = firebase.database().ref("team_mappings").orderByChild('score');
var snapshots = [];
function reversedChildren(snapshot) {
var children = [];
snapshot.forEach(function (child) { children.unshift(child); });
return children;
}
function addPlayerToLeaderBoard(snapshot) {
var key = snapshot.key;
var place = snapshots.indexOf(snapshot) + 1;
var score = snapshot.child('score').val();
$('#leaderboard').append(`<li><b>${key}: ${score}</li>`);
}
function parsePage(snapshot) {
var children = reversedChildren(snapshot);
children.forEach(function (child) {
players.push(child);
addPlayerToLeaderBoard(child);
});
pageCursor = children[children.length - 1];
}
function reloadPlayers() {
players = [];
pageCursor = null;
query.limitToLast(5).once('value').then(parsePage);
}
function loadMorePlayers() {
query.endAt(pageCursor).limitToLast(5).once('value').then(parsePage);
}
reloadPlayers();
$('#reload').on('click', reloadPlayers);
$('#load_more').on('click', loadMorePlayers);
Unfortunatelly, there is not a shortcut for this yet. However, if you are using Listview or Recyclerview as UI, you could simply solve this issue by reversing the UI,by reversing Listview or Recyclerview
For Recyclerview you could reverse as follows:
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
layoutManager.setReverseLayout(true);
layoutManager.setStackFromEnd(true);
recyclerView.setLayoutManager(layoutManager)
For Listview:
listView.setStackFromBottom(true);

Dynamically choose which properties to get using Linq

I have an MVC application with a dynamic table on one of the pages, which the users defines how many columns the table has, the columns order and where to get the data from for each field.
I have written some very bad code in order to keep it dynamic and now I would like it to be more efficient.
My problem is that I don't know how to define the columns I should get back into my IEnumerable on runtime. My main issue is that I don't know how many columns I might have.
I have a reference to a class which gets the field's text. I also have a dictionary of each field's order with the exact property It should get the data from.
My code should look something like that:
var docsRes3 = from d in docs
select new[]
{
for (int i=0; i<numOfCols; i++)
{
gen.getFieldText(d, res.FieldSourceDic[i]);
}
};
where:
docs = List from which I would like to get only specific fields
res.FieldSourceDic = Dictionary in which the key is the order of the column and the value is the property
gen.getFieldText = The function which gets the entity and the property and returns the value
Obviously, it doesn't work.
I also tried
StringBuilder fieldsSB = new StringBuilder();
for (int i = 0; i < numOfCols; i++)
{
string field = "d." + res.FieldSourceDic[i] + ".ToString()";
if (!string.IsNullOrEmpty(fieldsSB.ToString()))
{
fieldsSB.Append(",");
}
fieldsSB.Append(field);
}
var docsRes2 = from d in docs
select new[] { fieldsSB.ToString() };
It also didn't work.
The only thing that worked for me so far was:
List<string[]> docsRes = new List<string[]>();
foreach (NewOriginDocumentManagment d in docs)
{
string[] row = new string[numOfCols];
for (int i = 0; i < numOfCols; i++)
{
row[i] = gen.getFieldText(d, res.FieldSourceDic[i]);
}
docsRes.Add(row);
}
Any idea how can I pass the linq the list of fields and it'll cut the needed data out of it efficiently?
Thanks, Hoe I was clear about what I need....
Try following:
var docsRes3 = from d in docs
select (
from k in res.FieldSourceDic.Keys.Take(numOfCols)
select gen.getFieldText(d, res.FieldSourceDic[k]));
I got my answer with some help from the following link:
http://www.codeproject.com/Questions/141367/Dynamic-Columns-from-List-using-LINQ
First I created a string array of all properties:
//Creats a string of all properties as defined in the XML
//Columns order must be started at 0. No skips are allowed
StringBuilder fieldsSB = new StringBuilder();
for (int i = 0; i < numOfCols; i++)
{
string field = res.FieldSourceDic[i];
if (!string.IsNullOrEmpty(fieldsSB.ToString()))
{
fieldsSB.Append(",");
}
fieldsSB.Append(field);
}
var cols = fieldsSB.ToString().Split(',');
//Gets the data for each row dynamically
var docsRes = docs.Select(d => GetProps(d, cols));
than I created the GetProps function, which is using my own function as described in the question:
private static dynamic GetProps(object d, IEnumerable<string> props)
{
if (d == null)
{
return null;
}
DynamicGridGenerator gen = new DynamicGridGenerator();
List<string> res = new List<string>();
foreach (var p in props)
{
res.Add(gen.getFieldText(d, p));
}
return res;
}

How to find a word from arrays of characters?

What is the best way to solve this:
I have a group of arrays with 3-4 characters inside each like so:
{p, {a, {t, {m,
q, b, u, n,
r, c v o
s } } }
}
I also have an array of dictionary words.
What is the best/fastest way to find if the array of characters can combine to form one of the dictionary words? For example, the above arrays could make the words:
"pat","rat","at","to","bum"(lol)but not "nub" or "mat"Should i loop through the dictionary to see if words can be made or get all the combinations from the letters then compare those to the dictionary
I had some Scrabble code laying around, so I was able to throw this together. The dictionary I used is sowpods (267751 words). The code below reads the dictionary as a text file with one uppercase word on each line.
The code is C#:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Diagnostics;
namespace SO_6022848
{
public struct Letter
{
public const string Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
public static implicit operator Letter(char c)
{
return new Letter() { Index = Chars.IndexOf(c) };
}
public int Index;
public char ToChar()
{
return Chars[Index];
}
public override string ToString()
{
return Chars[Index].ToString();
}
}
public class Trie
{
public class Node
{
public string Word;
public bool IsTerminal { get { return Word != null; } }
public Dictionary<Letter, Node> Edges = new Dictionary<Letter, Node>();
}
public Node Root = new Node();
public Trie(string[] words)
{
for (int w = 0; w < words.Length; w++)
{
var word = words[w];
var node = Root;
for (int len = 1; len <= word.Length; len++)
{
var letter = word[len - 1];
Node next;
if (!node.Edges.TryGetValue(letter, out next))
{
next = new Node();
if (len == word.Length)
{
next.Word = word;
}
node.Edges.Add(letter, next);
}
node = next;
}
}
}
}
class Program
{
static void GenWords(Trie.Node n, HashSet<Letter>[] sets, int currentArrayIndex, List<string> wordsFound)
{
if (currentArrayIndex < sets.Length)
{
foreach (var edge in n.Edges)
{
if (sets[currentArrayIndex].Contains(edge.Key))
{
if (edge.Value.IsTerminal)
{
wordsFound.Add(edge.Value.Word);
}
GenWords(edge.Value, sets, currentArrayIndex + 1, wordsFound);
}
}
}
}
static void Main(string[] args)
{
const int minArraySize = 3;
const int maxArraySize = 4;
const int setCount = 10;
const bool generateRandomInput = true;
var trie = new Trie(File.ReadAllLines("sowpods.txt"));
var watch = new Stopwatch();
var trials = 10000;
var wordCountSum = 0;
var rand = new Random(37);
for (int t = 0; t < trials; t++)
{
HashSet<Letter>[] sets;
if (generateRandomInput)
{
sets = new HashSet<Letter>[setCount];
for (int i = 0; i < setCount; i++)
{
sets[i] = new HashSet<Letter>();
var size = minArraySize + rand.Next(maxArraySize - minArraySize + 1);
while (sets[i].Count < size)
{
sets[i].Add(Letter.Chars[rand.Next(Letter.Chars.Length)]);
}
}
}
else
{
sets = new HashSet<Letter>[] {
new HashSet<Letter>(new Letter[] { 'P', 'Q', 'R', 'S' }),
new HashSet<Letter>(new Letter[] { 'A', 'B', 'C' }),
new HashSet<Letter>(new Letter[] { 'T', 'U', 'V' }),
new HashSet<Letter>(new Letter[] { 'M', 'N', 'O' }) };
}
watch.Start();
var wordsFound = new List<string>();
for (int i = 0; i < sets.Length - 1; i++)
{
GenWords(trie.Root, sets, i, wordsFound);
}
watch.Stop();
wordCountSum += wordsFound.Count;
if (!generateRandomInput && t == 0)
{
foreach (var word in wordsFound)
{
Console.WriteLine(word);
}
}
}
Console.WriteLine("Elapsed per trial = {0}", new TimeSpan(watch.Elapsed.Ticks / trials));
Console.WriteLine("Average word count per trial = {0:0.0}", (float)wordCountSum / trials);
}
}
}
Here is the output when using your test data:
PA
PAT
PAV
QAT
RAT
RATO
RAUN
SAT
SAU
SAV
SCUM
AT
AVO
BUM
BUN
CUM
TO
UM
UN
Elapsed per trial = 00:00:00.0000725
Average word count per trial = 19.0
And the output when using random data (does not print each word):
Elapsed per trial = 00:00:00.0002910
Average word count per trial = 62.2
EDIT: I made it much faster with two changes: Storing the word at each terminal node of the trie, so that it doesn't have to be rebuilt. And storing the input letters as an array of hash sets instead of an array of arrays, so that the Contains() call is fast.
There are probably many way of solving this.
What you are interested in is the number of each character you have available to form a word, and how many of each character is required for each dictionary word. The trick is how to efficiently look up this information in the dictionary.
Perhaps you can use a prefix tree (a trie), some kind of smart hash table, or similar.
Anyway, you will probably have to try out all your possibilities and check them against the dictionary. I.e., if you have three arrays of three values each, there will be 3^3+3^2+3^1=39 combinations to check out. If this process is too slow, then perhaps you could stick a Bloom filter in front of the dictionary, to quickly check if a word is definitely not in the dictionary.
EDIT: Anyway, isn't this essentially the same as Scrabble? Perhaps try Googling for "scrabble algorithm" will give you some good clues.
The reformulated question can be answered just by generating and testing. Since you have 4 letters and 10 arrays, you've only got about 1 million possible combinations (10 million if you allow a blank character). You'll need an efficient way to look them up, use a BDB or some sort of disk based hash.
The trie solution previously posted should work as well, you are just restricted more by what characters you can choose at each step of the search. It should be faster as well.
I just made a very large nested for loop like this:
for(NSString*s1 in [letterList objectAtIndex:0]{
for(NSString*s2 in [letterList objectAtIndex:1]{
8 more times...
}
}
Then I do a binary search on the combination to see if it is in the dictionary and add it to an array if it is

Resources