I would like to do a partial sort of an array before sorting the complete array. The following Will return an array sorted on “sortOrder”
[folders sortedArrayUsingDescriptors:#[NSSortDescriptor sortDescriptorWithKey:#"sortOrder" ascending:YES]]
The array will look like this: [x, a, z, w, y]
but I would like to sort on “name” in ascending order when “sortOrder” is equal to zero first.
So the final array would look like this: [a, x, z, w, y]
Does anyone have a idea on how to do this?
"folders": [
{
"sortOrder": 0,
"name": "x",
},
{
"sortOrder": 0,
"name": "a",
},
{
"sortOrder": 1,
"name": "z",
},
{
"sortOrder": 3,
"name": "y",
},
{
"sortOrder": 2,
"name": "w",
}
]
Pass in two sort descriptors, one for "sortOrder" and the second for "name":
NSArray *descriptors = #[
[NSSortDescriptor sortDescriptorWithKey:#"sortOrder" ascending:YES],
[NSSortDescriptor sortDescriptorWithKey:#"name" ascending:YES],
];
NSArray *sortedArray = [folders sortedArrayUsingDescriptors:descriptors];
With this setup, any two items with the same sort order will then be sorted by name.
Related
So I got this array of object from database and I have to sort it in order:
by score (reverse)
by count (reverse)
by name
I've tried all three in reverse but what I need is the last one should not be reverse (DESC) here's my code:
new_data = data.sort_by{ |t| [t.score, t.matches_count, t.name] }.reverse
RESULT
[
{
"id": null,
"team_id": 939,
"name": "DAV",
"matches_count": 2,
"score": 100.0
},
{
"id": null,
"team_id": 964,
"name": "SAN",
"matches_count": 1,
"score": 100.0
},
{
"id": null,
"team_id": 955,
"name": "PAS",
"matches_count": 1,
"score": 100.0
},
{
"id": null,
"team_id": 954,
"name": "PAR",
"matches_count": 1,
"score": 100.0
},
{
"id": null,
"team_id": 952,
"name": "NUE",
"matches_count": 1,
"score": 100.0
}
]
Expected result should be sorted by name in ASC order not DESC I knew my code is wrong because the t.name is inside .reverse but if I will reorder it by name alone after the first 2 I will get the wrong answer it will just sort all by name not by the 3. I've also tried to .order("name DESC") from query so when reverse it will go ASC but no luck. Thank you!
data = [{:score=>100.0, :matches_count=>2, :name=>"DAV"},
{:score=>100.0, :matches_count=>1, :name=>"SAN"},
{:score=>100.0, :matches_count=>1, :name=>"PAS"},
{:score=>110.0, :matches_count=>1, :name=>"PAR"},
{:score=>100.0, :matches_count=>1, :name=>"NUE"}]
data.sort_by{ |h| [-h[:score], -h[:matches_count], h[:name]] }
#=> [{:score=>110.0, :matches_count=>1, :name=>"PAR"},
# {:score=>100.0, :matches_count=>2, :name=>"DAV"},
# {:score=>100.0, :matches_count=>1, :name=>"NUE"},
# {:score=>100.0, :matches_count=>1, :name=>"PAS"},
# {:score=>100.0, :matches_count=>1, :name=>"SAN"}]
You could also use Array#sort, which does not require that values to be sorted on in descending order be numeric, so long as they are comparable, that is, so long as they respond to the method :<=>.
data.sort do |t1, t2|
case t1[:score] <=> t2[:score]
when -1
1
when 1
-1
else
case t1[:matches_count] <=> t2[:matches_count]
when -1
1
when 1
-1
else
t1[:name] <=> t2[:name]
end
end
end
#=> <as above>
Instead of using - one can also try to reverse the sort using ! as demonstrated here: https://www.ruby-forum.com/t/sort-by-multiple-fields-with-reverse-sort/197361/2
So in your case, you could do:
new_data = data.sort_by{ |t| [!t.score, !t.matches_count, t.name] }
which should give you the same result as intended.
I would like to compare the run results of my pipeline. Getting the diff between jsons with the same schema though different data.
Run1 JSON
{"doc_id": 1, "entity": "Anthony", "start": 0, "end": 7}
{"doc_id": 1, "entity": "New York", "start": 30, "end": 38} # Missing from Run2
{"doc_id": 2, "entity": "Istanbul", "start": 0, "end": 8}
Run2 JSON
{"doc_id": 1, "entity": "Anthony", "start": 0, "end": 7} # same as in Run1
{"doc_id": 2, "entity": "Istanbul", "start": 0, "end": 10} # different end span
{"doc_id": 2, "entity": "Karim", "start": 10, "end": 15} # added in Run2, not in Run1
Based on the answer here my approach has been making a tuple out of the json values and then cogrouping using this large composite key made of some of the json values: How do I perform a "diff" on two Sources given a key using Apache Beam Python SDK?
Is there a better way to diff jsons with beam?
Code based on linked answer:
def make_kv_pair(x):
if x and isinstance(x, basestring):
x = json.loads(x)
""" Output the record with the x[0]+x[1] key added."""
key = tuple((x[dict_key] for dict_key in ["doc_id", "entity"]))
return (key, x)
class FilterDoFn(beam.DoFn):
def process(self, (key, values)):
table_a_value = list(values['table_a'])
table_b_value = list(values['table_b'])
if table_a_value == table_b_value:
yield pvalue.TaggedOutput('unchanged', key)
elif len(table_a_value) < len(table_b_value):
yield pvalue.TaggedOutput('added', key)
elif len(table_a_value) > len(table_b_value):
yield pvalue.TaggedOutput('removed', key)
elif table_a_value != table_b_value:
yield pvalue.TaggedOutput('changed', key)
Pipeline code:
table_a = (p | 'ReadJSONRun1' >> ReadFromText("run1.json")
| 'SetKeysRun1' >> beam.Map(make_kv_pair))
table_b = (p | 'ReadJSONRun2' >> ReadFromText("run2.json")
| 'SetKeysRun2' >> beam.Map(make_kv_pair))
joined_tables = ({'table_a': table_a, 'table_b': table_b}
| beam.CoGroupByKey())
output_types = ['changed', 'added', 'removed', 'unchanged']
key_collections = (joined_tables
| beam.ParDo(FilterDoFn()).with_outputs(*output_types))
# Now you can handle each output
key_collections.unchanged | "WriteUnchanged" >> WriteToText("unchanged/", file_name_suffix="_unchanged.json.gz")
key_collections.changed | "WriteChanged" >> WriteToText("changed/", file_name_suffix="_changed.json.gz")
key_collections.added | "WriteAdded" >> WriteToText("added/", file_name_suffix="_added.json.gz")
key_collections.removed | "WriteRemoved" >> WriteToText("removed/", file_name_suffix="_removed.json.gz")
Can you please help me sorting the dictionary below with value "Val1".
var data = ["key1" : ["val1": 1,"val2": 1],
"key2" : ["val1": 5,"val2": 2],
"key3" : ["val1": 0,"val2": 9]]
I am expecting this dictionary to be sorted like this. Highest values of 'Val1' to be on top (descending order)..
var data = [ "key2" : ["val1": 5,"val2": 2],
"key1" : ["val1": 1,"val2": 1],
"key3" : ["val1": 0,"val2": 9]]
As #Sulthan correctly pointed out Dictionary cannot be sorted. If you still want to, you'll get an Array as result.
let data = [
"key1": ["val1": 1,"val2": 1],
"key2": ["val1": 5,"val2": 2],
"key3": ["val1": 0,"val2": 9]
]
let result = data.sorted { $0.1["val1"]! > $1.1["val1"]! }
print(result)
[(key: "key2", value: ["val1": 5, "val2": 2]),
(key: "key1", value: ["val1": 1, "val2": 1]),
(key: "key3", value: ["val1": 0, "val2": 9])]
I have an array which contains numbers and alphabets something like:
newArray = ["1 a", "1 b" ,"2 c", "2 a"]
I would like to sort them in a way that the output is expected as follows:
newArray = ["2 a", "2 c" ,"1 a", "1 b"]
What I want to do is sort the numbers in descending order and if the numbers are same, then sort alphabetically
Can I implement a comparison function in sort_by or is there a way to do that using ruby sort
First you should use a better representation of your input. You can parse your existing array for example like this:
arr = newArray.map { |s| x,y = s.split; [x.to_i, y] }
# => [[1, "a"], [1, "b"], [2, "c"], [2, "a"]]
Then we can sort as we wish using sort_by:
arr.sort_by { |x,y| [-x, y] }
# => [[2, "a"], [2, "c"], [1, "a"], [1, "b"]]
Similar to #NiklasB. 's answer above (copied his sort_by)
arr.map(&:split).sort_by { |x,y| [-x.to_i, y] }
=> [["2", "a"], ["2", "c"], ["1", "a"], ["1", "b"]]
In a less elegant way, you can do that
arr.sort! do |p1, p2|
num1, str1 = p1.split(' ')
num2, str2 = p2.split(' ')
if (num1 != num2)
p2 <=> p1
else
p1 <=> p2
end
end
$stdout.puts arr
I need to parse and display solr facets which are returned in either JSON or Ruby formar:
Collections: [ "a", 1, "b", 2, "c", 3, "d", 4, ... ]
into
{"a"=>1, "b"=>2, "c"=>3, "d"=>4}
What is the cleanest way?
EDIT: Well now that we know what you actually want, a hash ...
collections = ["a", 1, "b", 2, "c", 3, "d", 4]
Hash[*collections]
# => {"a"=>1, "b"=>2, "c"=>3, "d"=>4}
Original answer: I may not understand your goal but...
collections = ["a", 1, "b", 2, "c", 3, "d", 4]
collections.each_slice(2).map{ |(x, y)| "#{x} - #{y}" }
# => ["a - 1", "b - 2", "c - 3", "d - 4"]
What i see you want to do is maybe a hash ? {a => "1", b => "2"} ??
If so, read below:
collections = [ "a", 1, "b", 2, "c", 3, "d", 4]
result = Hash[*collections.flatten]
result prints {"a"=>1, "b"=>2, "c"=>3, "d"=>4}