Check if a list and array are equal F# - arrays

I am trying to compare a list and an array and see if they are equal. Lets say we have a list list = [1;2;3;4] and an array ar = [|1;2;3;4|]. The function should return true if equal and false if not equal. I did it like this:
let list = [1;2;3;4]
let ar = [|1;2;3;4|]
let list' = Array.toList ar
(list = list')
So basically what I am doing is simply convert and compare two lists.. My question is is there any other way to do this, I mean which do not simply convert between list and array and which do not rely entirely on library functions.

You can use the fact that both lists and arrays (as well as most other collections) implement the seq<'a> interface (IEnumerable<T> in the .NET terms) and so you can just pass them to the functions from the Seq module without any conversions. This is just using an interface, so there is no overhead.
The easiest function I can think of for checking whether two sequences are the same is forall2, which takes two sequences and checks that a predicate holds for the elements pairwise. In this case, the predicate is just equality test (fun a b -> a = b) which you can abberviate as (=):
let list = [1;2;3;4]
let ar = [|1;2;3;4|]
Seq.forall2 (=) list ar

There are lots of ways you could do this. Here's one that compares the elements pairwise:
if list.Length = ar.Length then
Seq.zip list ar
|> Seq.forall (fun (a, b) -> a = b)
else false

F# docs say:
You compare two sequences by using the Seq.compareWith function. The function compares successive elements in turn, and stops when it encounters the first unequal pair. Any additional elements do not contribute to the comparison.
Which in your case becomes oneliner:
0 = Seq.compareWith (Comparer<_>.Default) list ar
Didn't check if it compiles. Use the Comparer.Default to compare primitives, otherwise, for complex custom types you may need to provide your own.

With Linq;
Enumerable.SequenceEqual (list, ar)

Based on this
let l = [1;2;3;4]
let a = [|1;2;3;4|]
let result = Seq.compareWith Operators.compare l a

Related

compare two arrays in order

I thought this would be pretty simple, but I seem to be getting things mixed up, and I haven't found anything on stackoverflow that quite matches my question.
I'm trying to write a function that can compare two arrays of file names to make sure their values match. They need to actually match in their position as well, so the order is crucial. In other words:
array1 = ["file1.html", "file2.html", "file3.html", "file4.html"]
array2 = ["file1.html", "file2.html", "file4.html", "file3.html"]
I would want a comparison between these two arrays to return as false, because of the difference in order (even though both arrays actually include the same values). I tried something like this:
matching = true
names1 = array1.map { |x| File.basename(x)}
names2 = array2.map { |x| File.basename(x)}
names1.each_with_index { |file,index|
if file != names2[index]
matching = false
end
}
return matching
This works, but I'm wondering if there's a cleaner, more foolproof way of comparing arrays in this way? Thanks!
You don't need to do anything of the sort. Default array equality operator compares arrays with order
array1 = %w[file1.html file2.html file3.html file4.html]
array2 = %w[file1.html file2.html file4.html file3.html]
array3 = %w[file1.html file2.html file3.html file4.html]
array1 == array2 # => false
array1 == array3 # => true
Example with comparing mapped values (if you have full paths in your arrays)
array1.map{|a| File.basename(a)} == array2.map{|a| File.basename(a) }
# or, as #mudasobwa would suggest
[array1, array2].map{|a| a.map(&File.method(:basename)) }.reduce(:==)
Use the last one if and only if a) you understand it completely and b)
you think it's a good idea.

Haskell Array Pattern in a function

Hi total Haskell beginner here: What does the pattern in a function for an array look like ? For example: I simply want to add +1 to the first element in my array
> a = array (1,10) ((1,1) : [(i,( i * 2)) | i <- [2..10]])
My first thought was:
> arraytest :: Array (Int,Int) Int -> Array (Int,Int) Int
> arraytest (array (mn,mx) (a,b):xs) = (array (mn,mx) (a,b+1):xs)
I hope you understand my problem :)
You can't pattern match on arrays because the data declaration in the Data.Array.IArray module for the Array type doesn't have any of its data constructors exposed. This is a common practice in Haskell because it allows the author to update the internal representation of their data type without making a breaking change for users of their module.
The only way to use an Array, therefore, is to use the functions provided by the module. To access the first value in an array, you can use a combination of bounds and (!), or take the first key/value pair from assocs. Then you can use (//) to make an update to the array.
arraytest arr = arr // [(index, value + 1)]
where
index = fst (bounds arr)
value = arr ! index
If you choose to use assocs, you can pattern match on its result:
arraytest arr = arr // [(index, value + 1)]
where
(index, value) = head (assocs arr) -- `head` will crash if the array is empty
Or you can make use of the Functor instances for lists and tuples:
arraytest arr = arr // take 1 (fmap (fmap (+1)) (assocs arr))
You will probably quickly notice, though, that the array package is lacking a lot of convenience functions. All of the solutions above are fairly verbose compared to how the operation would be implemented in other languages.
To fix this, we have the lens package (and its cousins), which add a ton of convenience functions to Haskell and make packages like array much more bearable. This package has a fairly steep learning curve, but it's used very commonly and is definitely worth learning.
import Control.Lens
arraytest arr = arr & ix (fst (bounds arr)) +~ 1
If you squint your eyes, you can almost see how it says arr[0] += 1, but we still haven't sacrificed any of the benefits of immutability.
This is more like an extended comment to #4castle's answer. You cannot pattern match on an Array because its implementation is hidden; you must use its public API to work with them. However, you can use the public API to define such a pattern (with the appropriate language extensions):
{-# LANGUAGE PatternSynonyms, ViewPatterns #-}
-- PatternSynonyms: Define patterns without actually defining types
-- ViewPatterns: Construct patterns that apply functions as well as match subpatterns
import Control.Arrow((&&&)) -- solely to dodge an ugly lambda; inline if you wish
pattern Array :: Ix i => (i, i) -> [(i, e)] -> Array i e
-- the type signature hints that this is the array function but bidirectional
pattern Array bounds' assocs' <- ((bounds &&& assocs) -> (bounds', assocs'))
-- When matching against Array bounds' assocs', apply bounds &&& assocs to the
-- incoming array, and match the resulting tuple to (bounds', assocs')
where Array = array
-- Using Array in an expression is the same as just using array
arraytest (Array bs ((i,x):xs)) = Array bs ((i,x+1):xs)
I'm fairly sure that the conversions to and from [] make this absolutely abysmal for performance.

Get the base array of an enumerated array

I need to sort an array based on the value as well as the index of each element, so I'd like to do something like this:
let a = [4,9,5,7].enumerate()
let b = a.sort { ... }
But then I need to convert b back to an array without the indices. My current solution is
let c = b.map { $0.1 }
But I was wondering, if there's a simpler way, since b is of the type EnumerateSequence<Array<Int>> and has a property base which holds the array that I want. Unfortunately base is internal and I don't know if there is any method that returns what I want.
Note: You might have noticed that this is Swift 2. While I need a solution in Swift 2 (if there is any), I am of course interested if there's a difference between Swift 2 and Swift 3.
But I was wondering, if there's a simpler way
No. let c = b.map { $0.1 } is simple.
This is slightly (2 characters) simpler:
let c = b.map { $1 }
map receives a tuple of two values, so you can either refer to the two values as $0.0 and $0.1, or as $0, and $1. When your closure uses only $0, then $0 is the entire tuple, so .0 and .1 refers to the individual items. When your closure mentions $1, then $0 is the first item of the tuple and $1 is the second item of the tuple.

F# Sort an Array with foldBack or fold.

I am trying to sort an Array by using fold or foldBack.
I have tried achieving this like this:
let arraySort anArray =
Array.fold (fun acc elem -> if acc >= elem then acc.append elem else elem.append acc) [||] anArray
this ofcourse errors horribly. If this was a list then i would know how to achieve this through a recursive function but it is not.
So if anyone could enlighten me on how a workable function given to the fold or foldback could look like then i would be createful.
Before you start advising using Array.sort anArray then this wont do since this is a School assignment and therefore not allowed.
To answer the question
We can use Array.fold for a simple insertion sort-like algorithm:
let sort array =
let insert array x =
let lesser, greater = Array.partition (fun y -> y < x) array
[| yield! lesser; yield x; yield! greater |]
Array.fold insert [||] array
I think this was closest to what you were attempting.
A little exposition
Your comment that you have to return a sorted version of the same array are a little confusing here - F# is immutable by default, so Array.fold used in this manner will actually create a new array, leaving the original untouched. This is much the same as if you'd converted it to a list, sorted it, then converted back. In F# the array type is immutable, but the elements of an array are all mutable. That means you can do a true in-place sort (for example by the library function Array.sortInPlace), but we don't often do that in F#, in favour of the default Array.sort, which returns a new array.
You have a couple of problems with your attempt, which is why you're getting a few errors.
First, the operation to append an array is very different to what you attempted. We could use the yield syntax to append to an array by [| yield! array ; yield element |], where we use yield! if it is an array (or in fact, any IEnumerable), and yield if it is a single element.
Second, you can't compare an array type to an element of the array. That's a type error, because compare needs two arguments of the same type, and you're trying to give it a 'T and a 'T array. They can't be the same type, or it'd be infinite ('T = 'T array so 'T array = 'T array array and so on). You need to work out what you should be comparing instead.
Third, even if you could compare the array to an element, you have a logic problem. Your element either goes right at the end, or right at the beginning. What if it is greater than the first element, but less than the last element?
As a final point, you can still use recursion and pattern matching on arrays, it's just not quite as neat as it is on lists because you can't do the classic | head :: tail -> trick. Here's a basic (not-so-)quicksort implementation in that vein.
let rec qsort = function
| [||] -> [||]
| arr ->
let pivot = Array.head arr
let less, more = Array.partition (fun x -> x < pivot) (Array.tail arr)
[| yield! qsort less ; yield pivot ; yield! qsort more |]
The speed here is probably several orders of magnitude slower than Array.sort because we have to create many many arrays while doing it in this manner, which .NET's Array.Sort() method does not.

Check if cell array is a subset of a nother in Matlab

I have two cell arrays of strings as follows
A={{a,b},{c},{d,e}}
B={{a,b},{c,d},{e}}
I want to check if A is a subset of B, meaning that each cell in A has a super-cell in B. In the given example it is not since A contains {d,e} while B does not have any cell that has those or more elements.
I think ismember should be useful in this case, but I just could not write down the logic.
Thank you!
Given A and B
A={{'a','b'},{'c'},{'d','e'}}
B={{'a','b'},{'c','d'},{'e'}}
We can define a function isSubset, as follows:
isSubset = #(superSet,subSet)isempty(setdiff(subSet, superSet));
And test it:
isSubset(B{1}, A{1}) %true
isSubset(B{2}, A{2}) %true
isSubset(B{3}, A{3}) %false
Now we can use isSubSet and cellfun to define a function isSubSetOfAny, which checks to see if a particular subset is a subset of any of a set of sets, like this:
isSubSetOfAny = #(superSetSet, subSet) any(cellfun(#(x)isSubset(x, subSet), superSetSet));
And test it:
isSubSetOfAny(B, A{1}) %True
isSubSetOfAny(B, A{2}) %True
isSubSetOfAny(B, A{3}) %True
Now we can use isSubSetOfAny plus cellfun (again) to define isEachMemberASubsetOfAny, which performs the operation you describe:
isEachMemberASubsetOfAny = #(superSetSet, subSetSet) all(cellfun(#(x)isSubSetOfAny(superSetSet, x), subSetSet));
And test it:
isEachMemberASubsetOfAny(B, A) %Returns false
A_1 = {{'a','b'},{'c'},{'e'}}; %Define a variant of `A`
isEachMemberASubsetOfAny(B, A_1) %Returns false
How about something like:
function tf = is_subset(A,B)
narginchk(2,2)
assert(iscell(A) && all(cellfun(#iscellstr,A)));
assert(iscell(B) && all(cellfun(#iscellstr,B)));
for ia=1:numel(A)
tf = false;
for ib=1:numel(B)
if all(ismember(A{ia},B{ib}));
tf = true;
break
end
end
if ~tf
break
end
end
end
With
[a,b,c,d,e] = deal('1','2','3','4','5');
A = {{a,b},{c},{d,e}};
B = {{a,b},{c,d},{e}};
is_subset(A,B) %# false
B = {{a,b},{c,d,e},{e}};
is_subset(A,B) %# true
Assuming a,b etc are strings you could do the following:
For each cell of A loop through B and see whether there is a cell in B for which all elements in the cell are member. Here is an example:
A={{'abc','b'},{'c'},{'d','e'}};
B={{'aabc','b'},{'c','d'},{'d','e'}}; %Remove the first a to return true
subset = true;
for i = 1:length(A)
found = false;
for j = 1:length(B)
found = found || all(ismember(A{i},B{j}));
end
subset = subset && found;
end
subset
What are the types of a, b, etc.? If they are strings, you can use setdiff to test whether one set is contained within another. Suitable use of cellfun and any or all should do it. Like so:
all(cellfun(#(a)any(cellfun(#(b)isempty(setdiff(a,b)),B)),A))
If they're some other type, you can make a simple m-file to check for a super-cell. Replace isempty(setdiff(a,b)) with a call to this function. It will have to loop through the elements of a and check for each one whether it exists in b.

Resources