سؤال

(filter-map (lambda (x y) (and (eq? x z)   y) ) list1 list2 ) 

in scheme, i have two list list1 and list2, if any element of list1 equal to z, i want to return corresponding to list2 element. i know only one element on list1 equal to z.

My code is working but i get a result such that '(bla) but i want to only a result such that bla how can i remove this parentheses?

هل كانت مفيدة؟

المحلول

You can use car to retrieve the first element in the output list, but I don't think filter-map is the best option here - after all you're not interested in the list of results returned by filter-map, only in a single element - and this is unavoidable, a list will be returned even if it's empty. Basically, you need to look for a value in an association list. Try this instead:

(cdr (assq 'z (map cons list1 list2)))
=> 'bla

Explanation:

  • (map cons list1 list2) builds an association list, where the elements in list1 are the keys and the elements in list2 are the values
  • assq looks for the key-value pair that has 'z as its key (using eq? for the comparisons), and returns that pair
  • cdr returns the value part of that pair

Alternatively, you can check if your interpreter has a hash table implementation available (useful if you have to efficiently perform more than one search), for instance in Racket:

(hash-ref (make-hasheq (map cons list1 list2)) 'z)
=> 'bla

Explanation:

  • (map cons list1 list2) builds an association list, where the elements in list1 are the keys and the elements in list2 are the values
  • make-hasheq creates a new hash table using the association list, and uses eq? when finding a value given the key
  • hash-ref returns the value corresponding to the key 'z

Be aware that both of the above options will raise an error when we attempt to obtain the value if the key wasn't present in list1, you have to decide how to handle this case if the need arises; for example we can return #f:

(let ((pair (assq 'z (map cons list1 list2))))
  (and pair (cdr pair)))

(hash-ref (make-hasheq (map cons list1 list2)) 'z
          (const #f))

نصائح أخرى

The naive approach would be to call car on the result, since car returns the first element of a list. But that would cause an error if no element matches - your function would return an empty list, and car will fail.

Some languages (i.e. Haskell) implement an option type. An option type is either empty or contains exactly one value. It's somewhat analogue to a list that can contains no more than one value. You can implement one for scheme and use it as the return type.

An alternative approach is to return the lists' first element, or #f (false) if no result was found. This approach is based on the fact that Scheme is a dynamic language.

While filter-map is nice and functional, an iterative answer might be the more straightforward (read: intelligible) way to approach this.

#lang racket
(define list1 '(a b z d))
(define list1a '(a b c d)) ; doesn't have 'z in it
(define list2 '(1 2 3 4))
(define (find-matching-pair lst1 lst2)
  (let loop ((l1 lst1)
             (l2 lst2))
    (cond ((null? l1) #f) ; didn't find it
          ((eqv? (car l1) 'z) (car l2)) ; this ASSUMES l2 is not shorter than l1
          (else (loop (cdr l1) (cdr l2))))))
(find-matching-pair list1 list2) ; => 3
(find-matching-pair list1a list2) ; => #f
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top