NSSortDescriptor custom alphanumeric order - nsmutablearray

I'm trying to sort an NSArray with a custom alphabetically order. The deal is that I have an Array with strings which are containing states of objects.
The available states are entered, process, ready, done.
Now when I sort them normally (in alphabetic order), the order would be incorrect (done, entered, process, ready).
I tried the following code to order it the right way:
NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:#"state" ascending:YES comparator:^(id obj1, id obj2) {
if ([obj1 isEqualToString:#"entered"] && [obj2 isEqualToString:#"process"]) {
return (NSComparisonResult) NSOrderedAscending;
}
else if ([obj1 isEqualToString:#"process"] && [obj2 isEqualToString:#"entered"]) {
return (NSComparisonResult) NSOrderedDescending;
}
else if ([obj1 isEqualToString:#"process"] && [obj2 isEqualToString:#"ready"]) {
return (NSComparisonResult) NSOrderedAscending;
}
else if ([obj1 isEqualToString:#"ready"] && [obj2 isEqualToString:#"process"]) {
return (NSComparisonResult) NSOrderedDescending;
}
else if ([obj1 isEqualToString:#"ready"] && [obj2 isEqualToString:#"done"]) {
return (NSComparisonResult) NSOrderedAscending;
}
else if ([obj1 isEqualToString:#"done"] && [obj2 isEqualToString:#"ready"]) {
return (NSComparisonResult) NSOrderedDescending;
}
else {
return (NSComparisonResult) NSOrderedSame;
}
}];
I also tried using just the first letters of the words, but it didn't work too.
When I'm using this comparator, it just don't order resp. the array keeps the "old" order.
What am I dining wrong? Didn't I understand sort comparators right?
Thanks for help, kind regards, Julian

I think that your scheme with strings is not suitable for what you are trying to do. To record states it is much better to use a different data model and take care of the appropriate strings in the view.
A common implementation involves an enum, which automatically increments if you define it like this:
typedef enum {
entered = 0,
processed,
ready,
done
} State;
Sorting now becomes trivial.
Your state should be of type State which is practically an integer. You will need to wrap it in an NSNumber if you want to use NSDictionary or NSArray, but it is certainly more readable if you create a custom object with a #property of type State.

I have to answer because I got a lot of code here. I now got the thing running. But there is a funny bug :)
NSString *str1 = (NSString *)obj1;
NSString *str2 = (NSString *)obj2;
if ([str1 isEqualToString:#"entered"] && [str2 isEqualToString:#"progress"]) {
return (NSComparisonResult) NSOrderedAscending;
}
else if ([str1 isEqualToString:#"entered"] && [str2 isEqualToString:#"ready"]) {
return (NSComparisonResult) NSOrderedAscending;
}
else if ([str1 isEqualToString:#"entered"] && [str2 isEqualToString:#"done"]) {
return (NSComparisonResult) NSOrderedAscending;
}
else if ([str1 isEqualToString:#"progress"] && [str2 isEqualToString:#"entered"]) {
return (NSComparisonResult) NSOrderedDescending;
}
else if ([str1 isEqualToString:#"progress"] && [str2 isEqualToString:#"ready"]) {
return (NSComparisonResult) NSOrderedAscending;
}
else if ([str1 isEqualToString:#"progress"] && [str2 isEqualToString:#"done"]) {
return (NSComparisonResult) NSOrderedAscending;
}
else if ([str1 isEqualToString:#"ready"] && [str2 isEqualToString:#"entered"]) {
return (NSComparisonResult) NSOrderedDescending;
}
else if ([str1 isEqualToString:#"ready"] && [str2 isEqualToString:#"progress"]) {
return (NSComparisonResult) NSOrderedDescending;
}
else if ([str1 isEqualToString:#"ready"] && [str2 isEqualToString:#"done"]) {
return (NSComparisonResult) NSOrderedDescending;
}
else if ([str1 isEqualToString:#"done"] && [str2 isEqualToString:#"entered"]) {
return (NSComparisonResult) NSOrderedDescending;
}
else if ([str1 isEqualToString:#"done"] && [str2 isEqualToString:#"progress"]) {
return (NSComparisonResult) NSOrderedDescending;
}
else if ([str1 isEqualToString:#"done"] && [str2 isEqualToString:#"ready"]) {
return (NSComparisonResult) NSOrderedDescending;
}
else {
return (NSComparisonResult) NSOrderedSame;
}
Now the bug: When I'm changing the order direction (ascending:YES / NO), the direction is right every second time I'm ordering ascending:YES (entered, progress, ready, done). Else it is a bit wrong: entered, progress, done, ready.
Does anybody can imagine why or has a solution for that? It's not a serious bug but I want to fix it though.
Thanks, Mundi, but I think I'll keep using my fuzzy style. I'm quite new to Cocoa / Objective C and this way makes more sense for me, right now. Nevertheless thanks for your effort!!

Related

CS50 pset5 Speller

That is my first post here, and I need help.
Speller's output for lalaland.txt is 958 words, but should be 955. (3 x "i'd").
I have tried to hard-code "i'd", but then output was ~850. (program declined all of "i'd").
tolstoy.txt - 13117, but must be 13008, most words are two-letters (Ha, ha, ga, Ma, I'd, etc.).
Same time other part of same word passing check.
Same situation with all other texts. Program passing and declining same words with no reason.
I have no idea what is happening.
Here is my load();
bool load(const char *dictionary)
{
FILE *inputFile = fopen(dictionary, "r");
if (inputFile == NULL)
{
return false;
}
while (true)
{
node *n = malloc(sizeof(node));
if (n == NULL)
{
return 1;
}
n->next = NULL;
int sc = fscanf(inputFile, "%s", n->word);
if (sc == EOF)
{
free(n);
break;
}
int bucket = hash(n->word);
if (table[bucket] == NULL)
{
table[bucket] = n;
}
else
{
n->next = table[bucket]->next;
table[bucket]->next = n;
}
sizeCount++;
}
fclose(inputFile);
return true;
}
And check();
bool check(const char *word)
{
int i = hash(word);
if (table[i] == NULL)
{
return false;
}
struct node *checker = malloc(sizeof(node));
checker = table[i];
while (true)
{
if (strcasecmp(checker->word, word) == 0)
{
return true;
}
if (checker->next == NULL)
{
break;
}
checker = checker->next;
}
free(checker);
return false;
}
Remember, table is an array of node pointers, not an array of nodes. Therefore, there is no memory allocated for a next or word element. These lines in load are accessing memory that does not belong to table[bucket]:
n->next = table[bucket]->next;
table[bucket]->next = n;
Since table is the head of the list, there is no need to allocate a node in check. If checker is a node pointer, initialized to table[bucket], the program will crawl the list just fine, and (should) only access allocated memory.
The memory violations are causing the unpredictable results. You could run valgrind -v to see the full report.

ACODE - spoj: Suggest what might be wrong with my approach

I tried this question ACODE from spoj. If you could suggest me, what might be wrong with my approach!
Link to the question: http://www.spoj.com/problems/ACODE/
My approach:
typedef long long ll;
ll dp[27][3];
ll acode(char *A,int n,int k)
{
if(k==0)
{
ll x,y;
x=acode(A,n,1);
y=acode(A,n,2);
return (x+y);
}
if(n<0)
return 0;
else if(n==0)
{
if(k==1)
return 1;
else
return 0;
}
if(dp[n][k] != 0)
return dp[n][k];
int m;
if(k==1)
m=A[n]-'0';
else
m=10*(A[n-1]-'0')+(A[n]-'0');
if(m<27 && m!=0)
{
if(k==1)
dp[n][k] = acode(A,n-1,1)+acode(A,n-1,2);
else
dp[n][k] = acode(A,n-2,1)+acode(A,n-2,2);
}
return dp[n][k];
}
int main()
{
char A[5001];
cin>>A;
cout<<A;
while(strcmp(A,0))
{
int l = strlen(A);
cout<<acode(A,l-1,0)<<endl;
cin>>A;
}
return 0;
}
Using top-down DP.Memoization of each index value for k=1 or k=2.

Isomorphic Strings

Given two strings s and t, determine if they are isomorphic.
Two strings are isomorphic if the characters in s can be replaced to get t.
All occurrences of a character must be replaced with another character while preserving the order of characters. No two characters may map to the same character but a character may map to itself.
For example,
Given "egg", "add", return true.
Given "foo", "bar", return false.
Given "paper", "title", return true.
Note:
You may assume both s and t have the same length.
I have this solution but it is taking too much time.
Any good solution will be appreciated
public boolean isIsomorphic(String s, String t) {
String resString1="",resString2="";
HashMap<Character,Integer> hashmapS = new HashMap();
HashMap<Character,Integer> hashmapT = new HashMap();
boolean flag = false;
for(int i = 0;i<s.length();i++)
{
char chS = s.charAt(i);
char chT = t.charAt(i);
if(hashmapS.containsKey(chS))
{
resString1 = resString1 + hashmapS.get(chS);
}
else
{
resString1 = resString1 + i;
hashmapS.put(chS, i);
}
if(hashmapT.containsKey(chT))
{
resString2 = resString2 + hashmapT.get(chT);
}
else
{
resString2 = resString2 + i;
hashmapT.put(chT, i);
}
}
if(resString1.equals(resString2))
return true;
else
return false;
}
/* Time complexity = O(n)*/
public static boolean isIsomorphic (String s1 , String s2){
if (s1 == null || s2 == null){
throw new IllegalArgumentException();
}
if (s1.length() != s2.length()){
return false;
}
HashMap<Character, Character> map = new HashMap<>();
for (int i = 0 ; i < s1.length(); i++){
if (!map.containsKey(s1.charAt(i))){
if(map.containsValue(s2.charAt(i))){
return false;
}
else{
map.put(s1.charAt(i), s2.charAt(i));
}
}
else{
if( map.get(s1.charAt(i)) != s2.charAt(i)){
return false;
}
}
}
return true;
}
In your implementation, you will come to know of the answer only after processing both strings completely. While in many negative test cases, answer can be determined seeing the first violation itself.
For e.g. consider 1000 character long strings: "aa.." and "ba....". An elegant solution would have to return seeing the second character itself of two strings, as 'a' cannot map to both 'a' and 'b' here.
You may find this article helpful. It also points to a C++ based solution.
Important thing to note are:
Since number of possible elements will be max pow(2, sizeof(char)), it is helpful to keep your own hash with ASCII code being the key itself. It gives significant improvement over the use of generic hash tables.
In Case of C++, use of std::urordered_map is better than std::map and std::stl as the later one uses Balanced Binary Search trees only.
Here is another implementation but with less memory usage.
public class IsoMorphic {
private static boolean isIsomorphic(String s, String t) {
if (s.length() != t.length()) {
return false;
}
char characters1[] = new char[26];
char characters2[] = new char[26];
char array1[] = s.toCharArray();
char array2[] = t.toCharArray();
for (int i=0; i<array1.length; i++) {
char c1 = array1[i];
char c2 = array2[i];
char character1 = characters1[c1-'a'];
char character2 = characters2[c2-'a'];
if (character1 == '\0' && character2 == '\0') {
characters1[c1-'a'] = array2[i];
characters2[c2-'a'] = array1[i];
continue;
}
if (character1 == array2[i] && character2 == array1[i]) {
continue;
}
return false;
}
return true;
}
public static void main(String[] args) {
System.out.println(isIsomorphic("foo", "bar")); // false
System.out.println(isIsomorphic("bar", "foo")); // false
System.out.println(isIsomorphic("paper", "title")); // true
System.out.println(isIsomorphic("title", "paper")); // true
System.out.println(isIsomorphic("apple", "orange")); // false
System.out.println(isIsomorphic("aa", "ab")); // false
System.out.println(isIsomorphic("ab", "aa")); // false
}
}
http://www.programcreek.com/2014/05/leetcode-isomorphic-strings-java/
You should be figuring out the algorithm by yourself though.
Two words are called isomorphic if the letters in single word can be remapped to get the second word. Remapping a letter means supplanting all events of it with another letter while the requesting of the letters stays unaltered. No two letters may guide to the same letter, yet a letter may guide to itself.
public bool isomorphic(string str1, string str2)
{
if (str1.Length != str2.Length)
{
return false;
}
var str1Dictionary = new Dictionary<char, char>();
var str2Dictionary = new Dictionary<char, char>();
var length = str1.Length;
for (int i = 0; i < length; i++)
{
if (str1Dictionary.ContainsKey(str1[i]))
{
if (str1Dictionary[str1[i]] != str2[i])
{
return false;
}
}
else
{
str1Dictionary.Add(str1[i], str2[i]);
}
if (str2Dictionary.ContainsKey(str2[i]))
{
if (str2Dictionary[str2[i]] != str1[i])
{
return false;
}
}
else
{
str2Dictionary.Add(str2[i], str1[i]);
}
}
return true;
}
public class Isomorphic {
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println(isIsomorphic("foo", "bar"));
System.out.println(isIsomorphic("bar", "foo"));
System.out.println(isIsomorphic("foo", "bar"));
System.out.println(isIsomorphic("bar", "foo"));
System.out.println(isIsomorphic("turtle", "tletur"));
System.out.println(isIsomorphic("tletur", "turtle"));
System.out.println(isIsomorphic("turtle", "tletur"));
System.out.println(isIsomorphic("tletur", "turtle"));
}
public static boolean isIsomorphic(String s1,String s2) {
if(s1.length()!=s2.length()) {
return false;
}
if(s1.length()==1) {
return true;
}
int c1;
int c2;
for(int i=0;i<s1.length()-1;i++) {
c1=s1.charAt(i);
c2=s1.charAt(i+1);
if(c1==c2) {
c1=s2.charAt(i);
c2=s2.charAt(i+1);
if(c1==c2) {
continue;
}else {
return false;
}
}else if(c1!=c2) {
c1=s2.charAt(i);
c2=s2.charAt(i+1);
if(c1!=c2) {
continue;
}else {
return false;
}
}
}
return true;
}
}
Comments are welcome !!
public bool IsIsomorphic(string s, string t)
{
if (s == null || s.Length <= 1) return true;
Dictionary<char, char> map = new Dictionary<char, char>();
for (int i = 0; i < s.Length; i++)
{
char a = s[i];
char b = t[i];
if (map.ContainsKey(a))
{
if (map[a]==b)
continue;
else
return false;
}
else
{
if (!map.ContainsValue(b))
map.Add(a, b);
else return false;
}
}
return true;
}
Here is my implementation...
private static boolean isIsmorphic(String string1, String string2) {
if(string1==null) return false;
if(string2==null) return false;
if(string1.length()!=string2.length())return false;
HashMap<Character,Character> map=new HashMap<>();
for(int i=0;i<string1.length();i++){
char c1=string1.charAt(i);
char c2=string2.charAt(i);
if(map.get(c1)!=null && !map.get(c1).equals(c2)){
return false;
}
map.put(c1, c2);
}
return true;
}
public class Solution {
public boolean isIsomorphic(String s, String t) {
int[] m = new int[512];
for (int i = 0; i < s.length(); i++) {
if (m[s.charAt(i)] != m[t.charAt(i)+256]) return false;
m[s.charAt(i)] = m[t.charAt(i)+256] = i+1;
}
return true;
}
}
I didn't find an answer without using Maps here, so posting my implementation which don't use additional memory.
Actually using HashMap to check if words are isomorphic is very slow on short words. On my computer using the implementation is faster up to 20 symbols in test words.
static boolean isIsomorphic(String s1, String s2) {
if (s1 == null || s2 == null) return false;
final int n = s1.length();
if (n != s2.length()) return false;
for (int i = 0; i < n; i++) {
final char c1 = s1.charAt(i);
final char c2 = s2.charAt(i);
for (int j = i + 1; j < n; j++) {
if (s1.charAt(j) == c1 && s2.charAt(j) != c2) return false;
if (s2.charAt(j) == c2 && s1.charAt(j) != c1) return false;
}
}
return true;
}
Java implementation using HashMap and HashSet. O(N) = n, O(S) = c, where c is the size of the character set.
boolean isIsomorphic(String s, String t){
HashMap<Character, Character> map = new HashMap<>();
HashSet<Character> set = new HashSet<>();
if(s.length() != t.length())
return false;
for (int i = 0; i < s.length(); i++) {
if(map.containsKey(s.charAt(i))){
if(map.get(s.charAt(i)) != t.charAt(i))
return false;
} else if(set.contains(t.charAt(i))) {
return false;
} else {
map.put(s.charAt(i), t.charAt(i));
set.add(t.charAt(i));
}
}
return true;
}
There are many different ways on how to do it. Below I provided three different ways by using a dictionary, set, and string.translate.
Here I provided three different ways how to solve Isomorphic String solution in Python.
This is the best solution I think
public boolean areIsomorphic(String s1,String s2)
{
if(s1.length()!=s2.length())
return false;
int count1[] = new int[256];
int count2[] = new int[256];
for(int i=0;i<s1.length();i++)
{
if(count1[s1.charAt(i)]!=count2[s2.charAt(i)])
return false;
else
{
count1[s1.charAt(i)]++;
count2[s2.charAt(i)]++;
}
}
return true;
}
C# soluation:
public bool isIsomorphic(String string1, String string2)
{
if (string1 == null || string2 == null)
return false;
if (string1.Length != string2.Length)
return false;
var data = new Dictionary<char, char>();
for (int i = 0; i < string1.Length; i++)
{
if (!data.ContainsKey(string1[i]))
{
if (data.ContainsValue(string2[i]))
return false;
else
data.Add(string1[i], string2[i]);
}
else
{
if (data[string1[i]] != string2[i])
return false;
}
}
return true;
}

Shortening this if condition

A few days ago I asked a question that might be a little unclear. Now I have written code that might illustrate the question better. Please look at the code below first:
int d;
d = DateTime.Today.Day;
if (d==1)
{
hyperlinkButton1.Background=new SolidColorBrush(Colors.Black);
}
else if (d==2)
{
hyperlinkButton2.Background=new SolidColorBrush(Colors.Black);
}
else if (d==3)
{
hyperlinkButton3.Background=new SolidColorBrush(Colors.Black);
}
else if (d==4)
{
hyperlinkButton4.Background=new SolidColorBrush(Colors.Black);
}
else if (d==5)
{
hyperlinkButton5.Background=new SolidColorBrush(Colors.Black);
}
else if (d==6)
{
hyperlinkButton6.Background=new SolidColorBrush(Colors.Black);
}
else if (d==7)
{
hyperlinkButton7.Background=new SolidColorBrush(Colors.Black);
}
else if (d==8)
{
hyperlinkButton8.Background=new SolidColorBrush(Colors.Black);
}
else if (d==9)
{
hyperlinkButton9.Background=new SolidColorBrush(Colors.Black);
}
else if (d==10)
{
hyperlinkButton10.Background=new SolidColorBrush(Colors.Black);
}
else if (d==11)
{
hyperlinkButton11.Background=new SolidColorBrush(Colors.Black);
}
else if (d==12)
{
hyperlinkButton12.Background=new SolidColorBrush(Colors.Black);
}
else if (d==13)
{
hyperlinkButton13.Background=new SolidColorBrush(Colors.Black);
}
else if (d==14)
{
hyperlinkButton14.Background=new SolidColorBrush(Colors.Black);
}
else if (d==15)
{
hyperlinkButton15.Background=new SolidColorBrush(Colors.Black);
}
else if (d==16)
{
hyperlinkButton16.Background=new SolidColorBrush(Colors.Black);
}
else if (d==17)
{
hyperlinkButton17.Background=new SolidColorBrush(Colors.Black);
}
else if (d==18)
{
hyperlinkButton18.Background = new SolidColorBrush(Colors.Black);
}
else if (d==19)
{
hyperlinkButton19.Background=new SolidColorBrush(Colors.Black);
}
else if (d==20)
{
hyperlinkButton20.Background=new SolidColorBrush(Colors.Black);
}
else if (d==21)
{
hyperlinkButton21.Background=new SolidColorBrush(Colors.Black);
}
else if (d==22)
{
hyperlinkButton22.Background=new SolidColorBrush(Colors.Black);
}
else if (d==23)
{
hyperlinkButton23.Background=new SolidColorBrush(Colors.Black);
}
else if (d==24)
{
hyperlinkButton24.Background=new SolidColorBrush(Colors.Black);
}
else if (d==25)
{
hyperlinkButton25.Background=new SolidColorBrush(Colors.Black);
}
else if (d==26)
{
hyperlinkButton26.Background=new SolidColorBrush(Colors.Black);
}
else if (d==27)
{
hyperlinkButton2.Background=new SolidColorBrush(Colors.Black);
}
else if (d==28)
{
hyperlinkButton28.Background=new SolidColorBrush(Colors.Black);
}
else if (d==29)
{
hyperlinkButton29.Background=new SolidColorBrush(Colors.Black);
}
else if (d==30)
{
hyperlinkButton30.Background=new SolidColorBrush(Colors.Black);
}
else
{
hyperlinkButton31.Background=new SolidColorBrush(Colors.Black);
}
My question (as a beginner) is this: is there any way in C# to shorten this condition by making the application determine which hyperlinkbutton background it has to change depending on the value of d?
Define an array of the relevant controls, and use the integer to key into the array, remembering that arrays are 0-based and not 1-based.
var buttons = new [] {
hyperlinkButton1,
hyperlinkButton2,
hyperlinkButton3,
hyperlinkButton4,
hyperlinkButton5,
hyperlinkButton6,
hyperlinkButton7,
hyperlinkButton8,
hyperlinkButton9,
// ...
}
//....
buttons[DateTime.Today.Day-1].Background=new SolidColorBrush(Colors.Black);
The array based approach is a good alternative at a general level to the multiple if statements but since this is also tagged as Silverlight, you might be interested in taking advantage of the FrameworkElement.FindName Method if you can rely on the convention of naming the HyperlinkButtons with a common prefix.
var hyperlinkButton = this.FindName("hyperlinkButton" + DateTime.Now.Day) as HyperlinkButton;
if (hyperlinkButton != null)
{
hyperlinkButton.Background = new SolidColorBrush(Colors.Black);
}
switch(d)
{
case 1: doThings(); break;
case 2: doThings2(); break;
case 3:
doSomeThings();
doMoreThings();
break;
default:
runThingsIfDIsNotListed();
break;
}
etc.

Drupal - Dispaly block if term page has no tagged nodes and no child terms?

How can I show a block on term pages if no nodes are tagged with that term and also there are no child terms?
Im using Drupal 6.
Thanks
Tricky one but you could use custom PHP code for your block display, something like this (assuming Drupal 6 here):
if (strstr($_GET['q'], 'taxonomy/term/')) {
$parts = explode('/', $_GET['q']);
$term = taxonomy_get_term($parts(2));
if ($term && $term->tid) {
$node_count = db_result(db_query('SELECT COUNT(nid) FROM {term_node} WHERE tid = %d', $term->tid));
if ($node_count == 0) {
return FALSE;
}
if (count(taxonomy_get_children($term->tid)) == 0) {
return FALSE;
}
return TRUE;
}
}
return TRUE;
And for Drupal 7:
if (arg(0) == 'taxonomy' && arg(1) == 'term' && is_numeric($arg(2))) {
$term = taxonomy_term_load(arg(2));
if ($term && $term->tid) {
if (db_query('SELECT COUNT(nid) FROM {taxonomy_index} WHERE tid = :tid', array(':tid' => $term->tid))->fetchField() == 0) {
return FALSE;
}
if (count(taxonomy_get_children($term->tid)) == 0) {
return FALSE;
}
return TRUE;
}
}
return TRUE;

Resources