I can sort alphabets or numbers using sort but how do I sort a mixture of alphabets and numbers.
(sort ["f" "g" "a" "b" "c"]) ; ==> ("a" "b" "c" "f" "g")
(sort [3 4 6 1 8 ]) ; ==> (1 3 4 6 8)
Question is, how do I sort this? ["g" "a" "c" 4 6 1] to get (1 4 6 "a" "c" "g")
The main issue is that you cannot compare a string with a number in a generic way: these are different types of values. When someone says "what's better: an apple or a house?", the first question that could probably pop into one's mind is "better in what way?" You can sort these two objects by many different properties, like size, cost or edibility. sort does not make the call about what property to use.
That's where sort-by function comes in. First it takes a keyfn, that when called on any element should produce its comparable property: in our case it's a string representation of a given element. Then it takes a collection, then (optionally) a comparator.
So you use str as your keyfn and you don't need a comparator, since comparison of strings is well-defined.
The resulting code is plain and simple:
(sort-by str ["g" "a" "c" 4 6 1]) ; => (1 4 6 "a" "c" "g")
You cannot compare a number and a string.
=> (sort ["g" "a" "c" 4 6 1])
ClassCastException java.lang.String cannot be cast to java.lang.Number
So to do what you want, you have to convert the numbers to strings then sort. For example:
=> (sort (map str ["g" "a" "c" 4 6 1]))
("1" "4" "6" "a" "c" "g")
Related
I am trying to create a function that takes a string in it's parameters. It's supposed to determine the highest and lowest numeric values in the string and return them unchanged.
Here's my code:
def high_and_low(numbers)
numbers.split
numbers.each {|x| x.to_i}
return numbers.max().to_s, numbers.min().to_s
end
Here's the error:
main.rb:5:in `high_and_low': undefined method `each' for "4 5 29 54 4 0 -214 542 -64 1 -3 6 -6":String (NoMethodError)
from main.rb:8:in `<main>'
You have not changed the value from string to array.
Replace numbers.split with numbers = numbers.split.
Also you will need to change from numbers.each { |x| x.to_i } to numbers.map!(&:to_i). Otherwise you don't save integers anywhere.
BTW you don't have to use () and return (if it's in the end) so you can write [numbers.max.to_s, numbers.min.to_s].
Something like this should work:
def high_and_low(numbers)
numbers = numbers.split.map(&:to_i)
[numbers.max, numbers.min].map(&:to_s)
end
high_and_low("4 5 29 54 4 0 -214 542 -64 1 -3 6 -6") #=> ["542", "-214"]
And bonus (one liner, not that you should write code this way):
def high_and_low(numbers)
numbers.split.map(&:to_i).sort.values_at(-1, 0).map(&:to_s)
end
high_and_low("4 5 29 54 4 0 -214 542 -64 1 -3 6 -6") #=> ["542", "-214"]
The other answer is a good approach too so I include it here:
numbers.split.minmax_by { |n| -n.to_i }
Ruby has some nice methods available to make this much more simple:
"2 1 0 -1 -2".split.map(&:to_i).minmax
# => [-2, 2]
Breaking it down:
"2 1 0 -1 -2".split # => ["2", "1", "0", "-1", "-2"]
.map(&:to_i) # => [2, 1, 0, -1, -2]
.minmax # => [-2, 2]
If you want string versions of the values back, compare two integers in a block. minmax will return the values at the corresponding positions in the source array:
"2 1 0 -1 -2".split.minmax{ |a, b| a.to_i <=> b.to_i }
# => ["-2", "2"]
or:
"2 1 0 -1 -2".split.minmax_by{ |a| a.to_i }
# => ["-2", "2"]
minmax and minmax_by do the heavy lifting. The first is faster when there isn't a costly lookup to find the values being compared such as this case where the values are in an array and only needed to_i to compare them.
The *_by version performs a "Schwartzian transform" which basically remembers the values in the block as they're compared so the costly lookup only occurs once. (Many of Enumerable's methods have *_by versions.) These versions of the methods can improve the speed when you want to compare two values that are nested, perhaps in arrays of hashes of hashes, or objects within objects within objects.
Note: When comparing string versions of numbers it's important to convert to a numeric value when comparing. ASCII and strings order differently than numbers, hence the use of to_i.
I am looking for a function that parses integer lists in Emacs Lisp, along the lines of Perl's Set::IntSpan. I.e., I would like to be able to do something like this:
(parse-integer-list "1-3, 4, 8, 18-21")
⇒ (1 2 3 4 8 18 19 20 21)
Is there an elisp library somewhere for this?
The following does what you want:
(defun parse-integer-list (str)
"Parse string representing a range of integers into a list of integers."
(let (start ranges)
(while (string-match "\\([0-9]+\\)\\(?:-\\([0-9]+\\)\\)?" str start)
(push
(apply 'number-sequence
(seq-map 'string-to-int
(seq-filter
'identity
(list (match-string 1 str) (match-string 2 str)))))
ranges)
(setq start (match-end 0)))
(nreverse (seq-mapcat 'nreverse ranges))))
The code loops over the incoming string searching for plain numbers or ranges of numbers. On each match it calls number-sequence with either just a number for a plain match or two numbers for a range match and pushes each resulting number sequence into a list. To account for push building the result backwards, at the end it reverses all ranges in the list, concatenates them, then reverses the result and returns it.
Calling parse-integer-list with your example input:
(parse-integer-list "1-3, 4, 8, 18-21")
produces:
(1 2 3 4 8 18 19 20 21)
Suppose we have a string str. If str contains only one character, for example, str = "1", then str[-1..1] returns 1.
But if the size (length) of str is longer than one, like str = "anything else", then str[-1..1] returns "" (empty string).
Why does Ruby interpret string slicing like this?
This behaviour is just how ranges of characters work.
The range start is -1, which is the last character in the string. The range end is 1, which is the second position from the start.
So for a one character string, this is equivalent to 0..1, which is that single character.
For a two character string, this is 1..1, which is the second character.
For a three character string, this is 2..1, which is an empty string. And so on for longer strings.
To get a non-trivial substring, the start position has to represent a position earlier than the end position.
For a single-length string, index -1 is the same as index 0, which is smaller than 1. Thus, [-1..1] gives a non-trivial substring.
For a string longer than a single character, index -1 is larger than index 0. Thus, [-1..1] cannot give a non-trivial substring, and by default, it returns an empty string.
Writing down the indices usually helps me:
# 0 1 2 3 4 5 6 7 8 9 10 11 12
str = 'a' 'n' 'y' 't' 'h' 'i' 'n' 'g' ' ' 'e' 'l' 's' 'e' #=> "anything else"
# -13 -12 -11 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1
You can refer to each character by either its positive or negative index. For example, you can use either 3 or -10 to refer to "t":
str[3] #=> "t"
str[-10] #=> "t"
and either 7 or -6 to refer to "g":
str[7] #=> "g"
str[-6] #=> "g"
Likewise, you can use each of these indices to retrieve "thing" via a range:
str[3..7] #=> "thing"
str[3..-6] #=> "thing"
str[-10..7] #=> "thing"
str[-10..-6] #=> "thing"
str[-1..1] however would return an empty string, because -1 refers to the last character and 1 refers to the second. It would be equivalent to str[12..1].
But if the string consists of a single character, that range becomes valid:
# 0
str = '1'
# -1
str[-1..1] #=> "1"
In fact, 1 refers to an index after the first character, so 0 would be enough:
str[-1..0] #=> "1"
I have created a dictionary out of two arrays using zip() like
list1 = [1,2,3,4,5]
list2 = [6,7,8,9,19]
dictionary1 = Dict(zip(list1,list2))
Now i want to sort this dictionary by key(list1) or by list2. Can somebody show me a way or function, how to realize it?
Sort also takes a by keyword, which means you can do:
julia> sort(collect(dictionary1), by=x->x[2])
5-element Array{Tuple{Int64,Int64},1}:
(1,6)
(2,7)
(3,8)
(4,9)
(5,19)
Also note that there is a SortedDict in DataStructures.jl, which maintains sort order, and there's an OrderedDict which maintains insertion order. Finally, there's a pull request which would allow direct sorting of OrderedDicts (but I need to finish it up and commit it).
While SortedDict may be useful if it is necessary to keep the dictionary sorted, it is often only necessary to sort the dictionary for output, in which case, the following may be what is required:
list1 = [1,2,3,4,5]
list2 = [6,7,8,9,19]
dictionary1 = Dict(zip(list1,list2))
sort(collect(dictionary1))
... which produces:
5-element Array{(Int64,Int64),1}:
(1,6)
(2,7)
(3,8)
(4,9)
(5,19)
We can sort by values with:
sort(collect(zip(values(dictionary1),keys(dictionary1))))
... which gives:
5-element Array{(Int64,Int64),1}:
(6,1)
(7,2)
(8,3)
(9,4)
(19,5)
The byvalue keyword for the sort function (or sort! for mutating/in place sorting) is useful for sorting dictionaries in order of their values (as opposed to their keys). The result will be of type OrderedDict from OrderedCollections.jl (it's also re-exported by DataStructures.jl).
list1 = [2,1,3,4,5]
list2 = [9,10,8,7,6]
dictionary1 = Dict(zip(list1,list2))
Sort by value (i.e. by list2):
sort(dictionary1; byvalue=true)
Output:
OrderedDict{Int64, Int64} with 5 entries:
5 => 6
4 => 7
3 => 8
2 => 9
1 => 10
Sort by key (i.e. by list1):
sort(dictionary1)
Output:
OrderedDict{Int64, Int64} with 5 entries:
1 => 10
2 => 9
3 => 8
4 => 7
5 => 6
The question requires me to Complete the Scheme function merge, which consumes two lists of sorted numbers (in an increasing order) and produces a list of numbers which consists of all the two consumed lists in sorted order.
For example,
(merge (list 1 4 5 9) (list -1 2 4)) => (list -1 1 2 4 4 5 9)
(merge (list 1 4 5 9) empty) => (list 1 4 5 9)
(merge empty (list 1 4 5 9)) => (list 1 4 5 9)
(merge empty empty) => empty
Thanks for helping out!!
Since this smells like homework, I won't write any code, but I will tell you that what are doing is part of the merge sort algorithm. Remember these two things:
In functional languages like Scheme, you are asking the question what value do I need to produce rather than what do I need to do
In Scheme, you often write more than one procedure to accomplish a single task
If you remember these two things and figure out which part of merge sort you need to implement, it should become fairly easy to figure out.